JS基础知识(三)- 作用域、闭包
# 1.几道面试题(以点带面)
说一下对变量提升的理解
说明this几种不同的使用场景
创建10个
<a>
标签,点击的时候弹出对应的序号如何理解作用域
实际开发中闭包的应用
# 2.涉及知识点
- 执行上下文
- this
- 作用域
- 作用域链
- 闭包
# 2.1 执行上下文(Execution-context)
执行上下文
- 范围:一段
<script>
或者一个函数 - 全局:变量定义、函数声明 【针对一段
<script>
里面】 - 函数:变量定义、函数声明、this、arguments
注意:要留意“函数声明” 和 “函数表达式” 的区别
console.log(a); // undefined
var a = 100;
fn('zhansan'); // zhangsan, 20
function fn(name) {
age = 20;
console.log(name, age);
var age;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2.2 this
this 要在执行时才能确认值,定义时无法确认
特殊情况:箭头函数体内的this
对象,就是定义该函数时所在的作用域指向的对象,而非使用时所在的作用域指向的对象
this的使用场景
- 作为构造函数执行
- 作为对象属性执行
- 作为普通函数执行 【this指向window】
- call、 apply、 bind
var a = {
name: 'A',
fn: function() {
console.log(this.name);
}
}
a.fn(); // A, this === a
a.fn.call({name: 'B'}); // B, this === {name: 'B'}
var fn1 = a.fn;
fn1(); // 空, this === window
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 2.3 作用域(action-scope)
作用域
- 全局作用域
- 函数作用域
- 块级作用域(ES6新增)
自由变量:一个变量在当前作用域没有定义,但被使用了
var a = 100;
function fn() {
var b = 200;
// 当前作用域没有定义的变量,即“自由变量”
console.log(a);
console.log(b);
}
fn();//输出100 200
var a = 100;
function F1() {
var b = 200;
function F2() {
var c = 300;
console.log(a); // a是自由变量
console.log(b); // b是自由变量
console.log(c);
}
F2();
}
F1();//输出100 200 300
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2.4 闭包(closure)
闭包的使用场景
- 函数作为返回值
- 函数作为参数传递
函数作为返回值
function F1() {
var a = 100;
// 返回一个函数(函数作为返回值)
return function() {
console.log(a); // 自由变量,去定义它时的父作用域寻找
}
}
// f1 得到一个函数
var f1 = F1();
var a = 200;
f1(); // 100
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
函数作为参数传递
function print(fn) {
let b = 200
fn()
}
let b = 100
function fnb() {
console.log(b)
}
print(fnb) // 100
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
所有的自由变量【闭包】的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!!
# 3.对前文问题的解答
# 3.1 创建10个 <a>
标签,点击的时候弹出对应的序号
for(var i = 0; i < 10; i++) {
a = document.createElement('a');
a.innerHTML = i + 1 + "<br>";
document.body.appendChild(a);
}
window.onload = function() {
var oA = document.getElementsByTagName('a');
for(var i = 0; i < oA.length; i++) {
oA[i].onclick = function(num) {
return function() {
alert(num);
}
}(i);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 3.2 实际开发中闭包的应用
// 闭包隐藏数据,只提供 API
function createCache() {
// 闭包中的数据,被隐藏,不被外界访问
const data = {}
return {
set: function(key,val) {
data[key] = val
},
get: function(key) {
return data[key]
}
}
}
const c = createCache()
c.set('a', 100)
console.log(c.get('a'))
// 封装变量,收敛权限。
function isFirstLoad() {
var _list = [];
return function(id) {
if (_list.indexOf(id) >= 0) {
return false;
} else {
_list.push(id);
return true;
}
}
}
var firstLoad = isFirstLoad();
console.log(firstLoad(10)); // true
console.log(firstLoad(10)); // false
console.log(firstLoad(20)); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34