用`let`定义的变量如何在`for`循环中起作用

时间:2016-06-30 09:04:47

标签: javascript for-loop let

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的新实例?

2 个答案:

答案 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”等。