我们可以这么理解问题:众所周知 javascript 是解释型的单线程编程语言,上述代码的执行过程实际是,执行 for 循环并把5个匿名函数的触发分别间隔 1-5 秒放入异步队列当中,而当异步队列的头节点开始执行时,for 循环早已经执行完毕,并且此时 i 作为全局作用域中的变量,其值为 6,这时无论异步队列中的头节点还是尾节点,在打印 i 变量的值并试图向上层作用域查找 i 时,获得的结果都是 6。
我们可以这么解决问题!
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
}
到底什么是闭包?
这是闭包吗? 技术上来讲也许是,但确切地说并不是。
这才是闭包的效果! 在上例中函数 bar 在定义自己的词法作用域以外的地方执行,在 foo 执行后垃圾回收器不知道 bar 什么时候会被调用,这使得对 foo 内部作用域的回收工作被阻止,而 bar 依然持有对该作用域的引用,这个引用就叫做
闭包
。循环与闭包
要说明闭包,for 循环是最常见的例子。
执行上述代码我们可以打印出0到9十个数字,但是如果执行下面这段代码呢?
正常情况下,我们对这段代码行为的预期是分别输出数字 1~5,每秒一次,每次一个。 但实际上,这段代码在运行时会以每秒一次的频率输出五次 6。
我们可以这么解决问题!
用容易理解的语言可以这么描述:IIFE 在执行完毕后,不知道延迟函数的回调什么时候执行,所以 IIFE 的作用域无法被销毁,其 j 变量的值被锁住。
块作用域与闭包
熟悉 ES6 的同学们都知道,下述代码也可以解决上面的 for 循环问题:
附录