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

Posted

技术标签:

【中文标题】用`let`定义的变量如何在`for`循环中起作用[重复]【英文标题】:How does variables defined with `let` act inside a `for` loop [duplicate] 【发布时间】:2016-11-02 06:39:43 【问题描述】:

在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.

我不明白为什么会有“变量i 的五个不同实例。

for 循环中的第一条语句总是执行一次,不是吗? 所以let 语句应该只执行一次... 一旦代码到达迭代的结尾,它就会检查第二条语句中的条件。

怎么会,根据他们写的,每次迭代都有一个i 的新实例?

【问题讨论】:

不是你要的,但我上周碰巧测试了这种行为,发现 IE 没有正确实现它。 (Chrome 做到了。) 在 ECMA 6 规范中,当使用 let 表达式时,每次迭代都会创建一个新的词法范围,链接到前一个范围。 ecma-international.org/ecma-262/6.0/… 要理解这一点,请将 let 更改为 var 并查看单击循环创建的元素时会发生什么 第一条语句只执行一次,但我相信第三条语句(I++)等于let i = i + 1,它执行了四次……对吗? @Jamiec,我了解发生了什么,但不完全是为什么 【参考方案1】:

当使用 let 表达式时,每次迭代都会创建一个新的词法范围,链接到前一个范围。

这意味着每个闭包都会捕获一个不同的实例。

这是根据ECMA 6 specification,但不确定它是否会在所有浏览器中以相同的方式工作。

也不确定性能影响。我宁愿谨慎使用此功能。

【讨论】:

在使用let IIFE 之前,为了达到同样的效果——性能可能更差。那么你的建议是什么? @LUH3417 我只是说我not sure 关于这种结构在不同浏览器中的性能。例如,查看为铬报告的这个问题bugs.chromium.org/p/v8/issues/detail?id=4762 @LUH3417 是的,可能 iffy-s 在性能方面更差。所以我现在最好不要推荐任何东西【参考方案2】:

javascript 中,变量传统上是函数范围的。块,例如 for...loop 语句,不会创建新范围。

如果您在函数中的任何位置(例如,在 for 循环中)使用 var 声明变量,则由于 hoisting,它将在范围顶部仅声明一次 ,并且在整个函数范围内只会有一个它的实例。

当您在 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 ", itemsi]); 
        // 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 变量仅限于最近的块(即大括号之间的任何代码段)。

在您的示例中,变量i 的新实例被声明,每次执行for...循环中的块。 i从 1 到 5,因此该块有 5 次执行,因此有 5 个变量实例。

它们将各自返回预期值“第 1 项已单击。”、“第 2 项已单击。”等

【讨论】:

重点是for 循环中的第一条语句总是执行一次。如下完成for (var i = 1; i++; i &lt; 5) let t = i; ... 不会引起任何问题。

以上是关于用`let`定义的变量如何在`for`循环中起作用[重复]的主要内容,如果未能解决你的问题,请参考以下文章

关于 ES6 的 let ,var和 const

关于ES6

for循环中关于var和let的区别

js变量var与let的区别

3.typescript定义变量

为啥 const 在 JavaScript 的某些 for 循环中起作用?