我不明白如何解释下面的代码以及为什么它不按预期工作:
for (var i = 0; i < 16; i++) {
setTimeout(function () {
console.log(i);
}, 1)
}
// Prints "16" 16 times
对此的一个解决方案是在for循环中使用let
而不是var
,或者
for (var i = 0; i < 16; i++) {
(function (k) {
setTimeout(function () {
console.log(k);
}, 100)
})(i)
}
// Print "0" to "15"
自我调用功能。
如果我对此有一个有根据的猜测,那就是var的范围与功能块相关联,或者在全局范围的情况下,for循环将超过setTimeout()
将调用的调用堆栈生成,因为Javascript是词法范围的,它将所有这些函数调回var i = 16
,而另一方面let i = 16
会将它保留到块中吗?
答案 0 :(得分:0)
在第一个示例中,循环变量i
周围有一个闭包。在第二种情况下,您可以通过制作i
的副本而不是使用k
来避免这种情况。避免闭包允许每次迭代保持其自己的值而不是与所有迭代共享i
。使用let
也可以解决问题,因为它会使循环变量i
具有块级范围,这意味着在每次迭代时,i
在技术上将是一个不同于前一个,所以每个嵌套函数都会获得对不同值的引用。
这完全是因为JavaScript的工作范围以及嵌套函数如何导致闭包,当嵌套函数从高阶函数引用变量并且嵌套函数的寿命比父函数长时,这会对代码产生副作用。在您的情况下,setTimeout
引用的函数将比其包含函数的寿命更长。