第一个例子
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值的四种状态,闭包会导致内存泄漏等问题。总算是了解了个清楚。下回写博客时候,给一起写出来。