第一个例子
1 | var a = []; |
这是一段很经典的代码。之前一直无法理解,为什么console.log(i)
的时候,i
是i而不是a[i]
所对应的值。
看似数组a
中,每个元素都取到了相应的i
。
但是。数组a
其实取到的是那个函数,i
的话,其实是在运行的时候读取的。
如果运行a[6]();
函数,那么实质上i
从全局作用域中读取,此时的i
已经是循环结束后的那个10了。
对此,只需稍作改造。1
2
3
4
5
6
7
8
9var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function(num) {
return function() {
console.log(num)
}
})(i)
}
a[6]();
我们把1
2
3a[i] = function () {
console.log(i);
};
改成了1
2
3
4
5a[i] = (function(num) {
return function() {
console.log(num)
}
})(i)
此时,循环中的i
作为num
的值传递给匿名立即执行函数,函数运行后返回一个函数,保持着对传进来的num
的引用。十个函数便有十个闭包。
此时a[i]
又等于函数。运行a[i]
时,就会读取闭包所保存的变量。
第二个例子
1 | /* |
本意是想,每一秒输出一个i
。但却会输出5个5。
原因和上面的一样,for循环在一瞬间执行完毕。console.log(i);
中的i
,则会沿着原型链向上查找。
此时全局变量中的i
,已经是for循环结束后的i了。
自己的解决方法
1 | for (var i = 0; i < 5; i++) { |
这是一开始自己写的解决方法。。虽然能用,但是一大坨看起来很不爽。于是看了看别人写的,顿时那个汗颜啊。
1 | for (var i = 0; i < 5; i++) { |
自己的错误在于return
了一个IIFE函数。事实上是没有必要的。循环中直接执行就行。
感想
到这儿的话,总算对闭包有所了解了。
包括之前迷迷糊糊的this
值的四种状态,闭包会导致内存泄漏等问题。总算是了解了个清楚。下回写博客时候,给一起写出来。