setTimeout中let和var的区别?

时间:2017-06-17 16:30:12

标签: javascript ecmascript-6

我知道let和var之间的区别。 let是块范围,var是功能范围。

for(var i=0; i< 3; i++){
    setTimeout(function(){
        console.log(i);
    }, 10);
}

output : 3
         3
         3

我知道上面的代码片段是如何工作的(console.log(i)当i的值为3时正在执行,因为i的范围是全局的。)

但是

for(let i=0; i< 3; i++){
    setTimeout(function(){
        console.log(i);
    }, 10);
}

output : 1
         2
         3

以上代码段令我困惑。根据我,它应该抛出引用错误(因为console.log(i)执行的时间,将在全局范围内查看i的值而不是在本地范围内,并且我不在全局中声明/定义。所以它应该给出引用错误。)

任何可以解释第二个循环如何在Runtime上工作的人?

3 个答案:

答案 0 :(得分:3)

在此上下文中使用let时,会在每次迭代时创建一个新的绑定/范围。如果您想在ES5中使用var实现类似的行为,则必须使用IIFE:

&#13;
&#13;
for (var i = 0; i < 3; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i);
    }, 10);
  })(i);
}
&#13;
&#13;
&#13;

答案 1 :(得分:3)

第二个示例(使用let)有效,因为函数将在声明范围时关闭范围内的所有变量。 for循环的每次迭代都使用let创建一个新变量,超时中的函数关闭变量并保持一个referance。在超时后取消引用该函数时,其闭包变量也是如此。

有关函数关闭的更多信息,请参阅How do JavaScript closures work

答案 2 :(得分:3)

这是关闭的魔力。在你的循环中

for(let i=0; i< 3; i++){
    setTimeout(function(){
        console.log(i);
    }, 10);
}

您正在宣布一项功能

function(){
  console.log(i);
}

此外,循环本身声明block

for(let i=0; i< 3; i++){
  // this is a block scope because it is contained in 
  // braces
}

使用let定义的变量是块作用域。

由于closure,您在循环中声明的函数可以访问其范围中声明的所有变量及其父范围,直到它被垃圾回收。

  

闭包是函数和词汇环境的结合   宣布该职能的人。这个环境包括   闭包时在范围内的任何局部变量   创建了。

当创建i使用的函数时,变量setTimeout范围内。对于循环的每次迭代,引用的ii的不同实例。

该函数一直存在,直到您声明的间隔通过。这就是为什么循环中声明的3个函数中的每一个都打印出i的值; 它在包含范围内声明,并且仍然可用于函数