我不明白如何解释下面的代码,以及为什么它不像预期的那样工作:
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的作用域绑定到函数块,或者在全局作用域的情况下,循环将击败setTimeout()
将产生的调用堆栈,因为Javascript是词法作用域,它回调所有这些函数作为var i = 16
,另一方面let i = 16
将保持它块?
在第一个示例中,在循环变量i
周围有一个闭包。在第二种情况下,您可以通过复制i
并使用k
来避免这种情况。避免闭包允许每个迭代保持自己的值,而不是与所有迭代共享i
。使用let
也可以解决问题,因为它将使循环变量i
具有块级作用域,这意味着在每次迭代中,i
在技术上将是与前一个不同的变量,因此每个嵌套函数将获得对不同值的引用。
这都是因为JavaScript中的作用域和嵌套函数导致闭包的方式,当嵌套函数引用高阶函数的变量并且嵌套函数的寿命比父函数长时,这对代码有副作用。在您的例子中,setTimeout
引用的函数将比包含它的函数存活的时间更长。