不久前,I asked a question使用此示例JS代码......
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
var copyindex = myindex;
MyAsync(mylist[myindex], function () { alert(copyindex); });
}
(答案主要是调用命名的函数,它将循环中的每个变量分开。)
我今天的问题是,上面的示例代码中实际发生了什么?每个警报调用都传递相同的copyindex变量,即使每次循环遍历时都会声明一个新的警报调用。
JS语言是否需要这种行为? (通过声明带有块范围的变量,我真的将它声明为函数的顶部。)
或者,这可能是我测试的少数浏览器的实现细节,未来的JS平台没有义务将 copyindex 的许多实例链接在一起吗?
答案 0 :(得分:2)
每个警报调用都会传递相同的copyindex变量,即使每次都声明了一个新的...
这是一个常见的误解。 var
没有块范围,因此您的代码真的就是:
var copyindex;
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
copyindex = myindex;
MyAsync(mylist[myindex], function () { alert(copyindex); });
}
更多(在我的博客上):Poor, misunderstood var
,当然,在规范中 - 它已在§10.5 - Declaration Binding Instantiation中介绍。
ES6将通过let
关键字引入块范围变量。您使用的地方let
关键字非常重要。
让我们以var
:
for (var x = 0; x < 3; ++x) {
setTimeout(function() { console.log("x = " + x); }, 0);
}
console.log("typeof x = " + typeof x);
我们知道会给我们
number 3 3 3
...因为var
被提升到范围的顶部,因此我们创建的所有三个函数都使用相同的x
,并且x
存在于循环之外。 (当然,我们首先看到typeof
结果,因为其他结果发生在最小超时之后。)
如果我们在同一个地方使用let
:
for (let x = 0; x < 3; ++x) {
setTimeout(function() { console.log("x = " + x); }, 0);
}
console.log("typeof x = " + typeof x);
我们得到了
undefined 3 3 3
...因为x
的范围是循环,而不是循环迭代。这三个函数仍使用相同的x
,唯一的区别是循环外不存在x
。
但是如果我们在主体中使用let
:
for (let n = 0; n < 3; ++n) {
let x = n;
setTimeout(function() { console.log("x = " + x); }, 0);
}
console.log("typeof x = " + typeof x);
我们得到了
undefined 0 1 2
...因为现在x
的范围是每次迭代的主体,而不是整个循环。
您可以使用NodeJS自行尝试,只需确保为其提供--harmony
标志即可启用ES6功能。