了解闭包

时间:2015-11-29 09:28:27

标签: javascript closures

我正在阅读高级JavaScript文本并遇到这些代码,我认为作者试图展示闭包但没有解释代码。我几个小时都在盯着这些代码,但仍然无法弄清楚为什么它们会产生不同的输出。

for (var i = 0; i <= 2000; i += 1000) {
    setTimeout(function () {
      console.log('i value in closure is ' + i);
    }, i);
}
//Output
// i value in closure is 2000
// i value in closure is 2000
// i value in closure is 2000`

for (var i = 0; i <= 2000; i += 1000) { 
  (function (i) { 
    setTimeout(function () { 
      console.log('i value in closure is ' + i); 
    }, i); 
  })(i); 
}
//Output
// i value in closure is 0
// i value in closure is 1000 
// i value in closure is 2000`

1 个答案:

答案 0 :(得分:2)

在第一个代码块中,for循环将运行完成。每次通过循环将在未来的某个时间安排setTimeout()呼叫。但是,当setTimeout()实际触发时,i的值将是所有for次调用的setTimeout()循环结束处的值。

在第二个代码块中,for循环将再次运行完成,但每次通过for循环时,它会创建一个新的函数闭包,如果{{1}则“捕获”该值为每个计时器回调单独分配,因此它会在i回调中显示所需的i值,因为它已为每个计时器单独保存。

你可以想到你的第二个代码更像是这样:

setTimeout()

你的第二个代码块和这个扩展代码之间的唯一区别是你的第二个代码块使用了anonmymous IIFE而不是这里显示的命名function myTimer(index) { setTimeout(function () { console.log('i value in closure is ' + index); }, index); } for (var i = 0; i <= 2000; i += 1000) { myTimer(i); } 函数,但执行是相同的。在myTimer()循环中使用此函数会创建一个Javascript函数闭包,可以保存for的值,以便在i稍后调用其回调时,{{1}的唯一值可用于回调,它为每次调用该函数执行此操作。

施工:

setTimeout()

被称为 立即调用的函数表达式 (缩写为IIFE),是一种在Javascript中创建闭包的快捷方法。

有关该主题的更多信息,请参阅此先前的答案:Asynchronous Process inside a javascript for loop