用`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 < 5) let t = i; ...
不会引起任何问题。以上是关于用`let`定义的变量如何在`for`循环中起作用[重复]的主要内容,如果未能解决你的问题,请参考以下文章