2017-06-13 44 views
0

我一直在试图理解为什么下面的代码段表现为它的作用:闭合如何影响for循环?

for (var i=1; i<=5; i++) { 
     setTimeout(function timer(){ 
      console.log(i); 
     }, i*1000); 
    } //prints 6 five times with a gap of one second in between each 

为什么6?我看到了一些解释,但我仍然无法理解。另外为什么下面的代码工作?

for (var i=1; i<=5; i++) { 
     (function(){ 
      var j = i; 
      setTimeout(function timer(){ 
       console.log(j); 
      }, j*1000); 
     })(); 
    } 
+0

第二个代码片段在每个循环中创建一个'i'的副本,所以当超时实际触发时,您会看到保存状态为'i'。第一个例子总是引用相同的'i',因此当超时最终触发时,它们都显示'i'的最终值。 – Sirko

回答

0

你传递setTimeout()相同拉姆达五次,每次用相同的循环变量,i参考。对于每个呼叫,拉姆达被退出循环后,评价,当i等于6i++,检查是否i <= 5,如果不是,中断循环的)。

拉姆达具有参考变量本身,而不是其在拉姆达被创建的时间值。这在大多数情况下非常有用。只是不是这个。

var j;版本有两个 lambda。 var j = i;立即执行,当前值为i。这将创建一个新的变量j,该lambda是本地的。 j用当前执行外部lambda时的当前值i进行初始化。因此,在这种情况下,你给setTimeout()你不妨考虑五个不同的lambda表达式,有五个不同的变量,都命名为j,但有五个不同的值。

内拉姆达在以后执行,但它使用j

不同的是,代码创建了一个独特的位置来存储每个的值i

最后一点:在其他一些语言,这会工作:

for (var i=1; i<=5; i++) { 
    var j = i; 
    setTimeout(function timer(){ 
     console.log(j); 
    }, j*1000); 

} 

在JavaScript中,它没有。 j的范围有所不同。在JavaScript中,这种情况下只有一个j。这就是为什么使用立即执行的功能:为了确保将有多个j