通过Javascript / Node中的闭包了解variables捕获

除了标准之外,在JavaScript中是否有variables捕获的确切来源(阅读标准很痛苦)?

在下面的代码中, i被值复制:

 for (var i = 0; i < 10; i++) { (function (i) { process.nextTick(function () { console.log(i) }) }) (i) } 

所以它打印1..10。 process.nextTick是节点中setTimeout(f,0)的模拟。

但在接下来的代码中,我似乎没有被复制:

 for (var i = 0; i < 10; i++) { var j = i process.nextTick(function () { console.log(j) }) } 

它打印9 10次。 为什么? 我对参考文献/一般文章更感兴趣,而不是解释这个具体的捕获案例。

我没有一个方便的参考。 但底线是:首先,你明确地将i传递给一个匿名函数,它创build一个新的范围。 你不是在第二次为ij创build一个新的范围。 而且,JavaScript总是捕获variables,而不是值。 所以你也可以修改我。

JavaScript var关键字具有function范围,而不是范围范围。 所以for循环不会创build一个范围。

请注意,非标准let关键字具有本地范围。

在第二个例子中,它被复制(或分配),只是variablesj只有一个副本,并且它将具有最后一个variablesj的值(它是for循环的最后一个variables)。 您需要一个新的函数闭包来for循环的每一次创build一个variables的新副本。 你的第二个例子只有一个variables,这个variables对于你的for循环的所有转换是共同的,因此它只能有一个值。

我不知道有关这个话题的任何明确的写法。

javascript中的variables被限定在函数级别。 在JavaScript中没有块范围。 因此,如果你想为for循环的每一个版本添加一个variables的新版本,你必须使用一个新的函数(创build一个函数闭包)来每次通过for循环捕获这个新的值。 如果没有函数闭包,那么这个variables只有一个值,这个variables的所有用户都是共同的。

当你声明一个variables,如你的var j = i; 在函数的开头以外的某个位置,JavaScript将定义提升到函数的顶部,并且您的代码变成等同于此:

 var j; for (var i = 0; i < 10; i++) { j = i; process.nextTick(function () { console.log(j) }) } 

这就是所谓的variable hoisting ,如果你想了解更多的信息,这是一个你可以谷歌的术语。 但是,重点是只有函数作用域,所以在函数的任何地方声明的variables实际上是在函数的顶部声明一次,然后分配给函数中的任何地方。

在JavaScript中,函数variables定义在自己范围之外的variables中,以便对variables具有“活跃”引用,而不是在特定时间对其值的快照。

所以在你的第二个例子中,你创build了十个匿名函数(在process.nextTick(function(){...}) )中,它包含variablesj (和i ,当匿名函数被创build时它们总是具有相同的值)。 每个函数在外部for循环完全运行之后使用j的值,所以在调用每个函数时j=i=10 。 也就是说,首先你的for循环完全运行,然后你的匿名函数运行,并使用已经设置为10的j的值!

在你的第一个例子中,情况有些不同。 通过在自己的匿名函数中将调用包装到process.nextTick(...)中,并通过调用包装函数将函数本地作用域中的值绑定到函数参数i (并附带地将旧variablesi 映射到函数参数i ) ,那么您捕获当时的variablesi的值,而不是保留内部匿名函数附件中的值变化的i封闭引用

为了澄清你的第一个例子,试着改变匿名包装函数来使用一个名为x(function (x) { process.nextTick(...); })(i) )的参数。 在这里,我们清楚地看到x在当前调用匿名函数时的值,因此它将得到for循环中的每个值(1..10)。

Mozilla开发者networking有一个非常好的写法:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures