在documentation for the let
statement in MDN中,有以下示例代码:
var list = document.getElementById("list");
for (let i = 1; i <= 5; i++) {
let item = document.createElement("li");
item.appendChild(document.createTextNode("Item " + i));
item.onclick = function (ev) {
console.log("Item " + i + " is clicked.");
};
list.appendChild(item);
}
然后他们说:
上面的例子按预期工作,因为它的五个实例 (匿名)内部函数是指的五个不同实例 变量我。
我不明白为什么变量i
有五个不同的实例。
for
循环中的第一个语句总是执行一次,不是吗?
所以let
语句应该只执行一次...
一旦代码到达迭代结束,它将检查第二个语句中的条件。
为什么根据他们写的内容,每次迭代都有i
的新实例?
答案 0 :(得分:3)
当使用let表达式时,每次迭代都会创建一个链接到前一个范围的新词法范围。
这意味着每个闭包都会捕获不同的实例。
根据ECMA 6 specification,但不确定它在所有浏览器中的工作方式是否相同。
也不确定性能影响。我宁愿小心使用这个功能。
答案 1 :(得分:0)
在Javascript中,变量传统上是功能范围。块(例如...循环语句)不会创建新范围。
如果您在函数中的任何位置使用var
声明变量(例如,在for循环中),则仅在范围顶部声明一次,这要归功于{ {3}},并且在整个函数范围内只有一个实例。
在for ...循环中调用回调时,可能会导致问题。
// with hoisting, i is only declared once
for (var i in items) {
// the fn is called items.length times, before any callback is invoked
_fetchItems(items[i], function() {
console.log("fetched for ", items{i]);
// for all callbacks, i is the same value items.length-1
// because they are called after the loop is complete
});
}
或者在你的例子中:
// with hoisting, i is only declared once
for (var i = 1; i <= 5; i++) {
// with hoisting, item is only declared once
var item = document.createElement("li");
item.appendChild(document.createTextNode("Item " + i));
// this function will be called after the for...loop is complete
// so i value is unique: 5 + 1 = 6
item.onclick = function (ev) {
// => always return "Item 6 is clicked"
console.log("Item " + i + " is clicked.");
};
list.appendChild(item);
}
相反,let
变量仅限于最近的块(即花括号之间的任何代码段)。
在您的示例中,为for ...循环内的块的每次执行声明了变量i
的新实例。 i
从1到5,因此有5次执行该块,因此有5个变量实例。
他们将返回预期值“单击项目1。”,“单击项目2”等。