# 闭包
# 闭包是啥
MDN中这么定义闭包: 闭包是 函数 和 声明该函数的词法环境 的集合
// 例子:函数工厂
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 闭包和函数作用域的联系
函数作用域是产生闭包的原因
# 为什么要用闭包
闭包允许将函数与其所操作的某些数据(环境)关联起来。
这显然类似于面向对象编程。面向对象编程中,对象允许我们将某些数据与一个或多个方法相关联
用闭包模拟私有方法(数据隐藏和封装 )
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */
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
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
计数器counter1和counter2是相互独立的,每个闭包都是引用自己词法作用域内的变量privateCounter,在一个闭包中对变量的修改不会影响到另一个闭包中的变量
# 怎么使用闭包
闭包中常见的问题: for click 问题
const lists = document.querySelectorAll('li')
for(var i = 0; i < lists.length; i++) {
lists[i].onclick = function () {
alert(i)
}
}
1
2
3
4
5
6
2
3
4
5
6
问题: 上面的代码,每次点击的时候都是alert(3)
原因: 作用域问题,在点击的时候再去取i的值,已经是lists.length了,使用let创建i,不会出现这个问题
解决方法: 使用闭包 或者 使用let创建i
// 闭包解决
const lists = document.querySelectorAll('li')
for(var i = 0; i < lists.length; i++) {
(function() {
lists[i].onclick = function() {
alert(i)
}
})(i)
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
原因: 在上面的情况中,i是全局变量,在onclick时间触发的时候,访问的是全局变量i,所以i一直都是3,如果放在闭包中执行,实参传递到形参的时候,非引用类型的实参会复制一份给形参,而不是共享一份