setTimeout回调Explination

时间:2016-11-08 13:47:57

标签: javascript node.js lexical-scope

我不明白如何解释下面的代码以及为什么它不按预期工作:

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会将它保留到块中吗?

1 个答案:

答案 0 :(得分:0)

在第一个示例中,循环变量i周围有一个闭包。在第二种情况下,您可以通过制作i的副本而不是使用k来避免这种情况。避免闭包允许每次迭代保持其自己的值而不是与所有迭代共享i。使用let也可以解决问题,因为它会使循环变量i具有块级范围,这意味着在每次迭代时,i在技术上将是一个不同于前一个,所以每个嵌套函数都会获得对不同值的引用。

这完全是因为JavaScript的工作范围以及嵌套函数如何导致闭包,当嵌套函数从高阶函数引用变量并且嵌套函数的寿命比父函数长时,这会对代码产生副作用。在您的情况下,setTimeout引用的函数将比其包含函数的寿命更长。