有人解释这个(var和let in for循环之间的行为差异)吗?
经典面试问题(闭幕):
let a = [];
for (var i=0; i<10; i++) {
a[i] = function() {
console.log(i,);
}
}
a[0](); // 10
a[1](); // 10
如果我们使用let:
let a = [];
for (let i=0; i<10; i++) { // var => let
a[i] = function() {
console.log(i);
}
}
a[0](); // 1
a[1](); // 2
是的,我正常并且正如预期的那样使用'let'。 我想到的第一个想法是,不要支持关闭。但不,它支持。 (以下在Chrome上测试过):
function bb() {
let b = 1;
return function() {
console.log(b);
}
}
bb()(); // 1, means a closure is created
然后我的第二个解释是:当使用let in for循环时。对于每个循环,它会重复创建一个新的i。我在Chrome调试器中证明了这一点。
问题是:
如果在for循环中的每个循环中创建了i。它如何不断增加???为什么它不只是保持为0,因为我们声明它是否每次都被创建?
for (let i=0; .......)
答案 0 :(得分:4)
从您的示例中,每次迭代都会创建“词法声明”let i
的环境。但是,for
循环使用以前的环境来创建下一个环境。因此,当增量发生时,它从它停止的地方开始。否则,使用let
声明i
会产生无限循环(即i
始终为<10
)。
工作原理:
在for循环body evaluation中,'test'和'result'之后的步骤是CreatePerIterationEnvironment(perIterationBindings),它声明了一个新环境,并将所有绑定初始化为它们的上一个已知值:thisIterationEnv.InitializeBinding(bn, lastValue)
。完成后,新环境将设置为当前环境,并且“增量”步骤将开始。
定义:
InitializeBinding(N,V)设置环境记录中已存在但未初始化的绑定的值。字符串值N是绑定名称的文本。 V是绑定的值,是任何ECMAScript语言类型的值。
答案 1 :(得分:0)
第一个,错误的(意外的)结果只是因为闭包可以访问外部函数变量的更新值(最后闭包中的变量'i'是10);
第二个,使用let
声明变量i
以将其标记为block variable
,这意味着闭包会立即获得i
(如IIFE)。