这个问题在这里已经有了答案:
Explanation of `let` and block scoping with for loops
(4 个回答)
2年前关闭。
请考虑下面的片段 -
for(let i = 1; i <= 5; i++) {
setTimeout(function(){
console.log(i);
},100);
}
在这种情况下,在
setTimeout
内记录将包含变量 i
的值根据for循环的每次迭代,即日志如下1
2
3
4
5
为此,我已经阅读了互联网上的解释,例如 -
let
为每个循环创建一个变量声明,这是 block 级声明。所以基本上它在 { }
内创建了一个范围.但我对这个说法有点困惑。如果
let
为每个循环创建一个变量声明,它不会总是初始化为 1
根据循环初始化语句 let i=1
?此外,变量
i
在循环 block 之外声明、初始化和递增,即 for
中的花括号循环语句。所以,在每次迭代中不是同一个变量i
被增量和利用? let
到底是怎么回事?为每个循环创建一个变量声明并具有先前迭代的值?
最佳答案
一般说明
当您使用 let
在 for
像你展示的循环结构,有一个新变量 i
为循环的每次调用创建,该循环的范围仅限于循环 block (在循环外不可访问)。
循环的第一次迭代从 for
中获取它的值。循环初始化程序( i = 1
在您的示例中)。其他新i
每次循环迭代创建的变量从 i
获取它们的值。对于循环的先前调用,而不是来自 i = 1
这就是为什么它们没有全部初始化为 1
.
因此,每次循环都会有一个新变量 i
它与所有其他的分开,每个新的都用前一个的值初始化,然后由 i++
处理在 for
循环声明。
对于您的 ES6 代码:
for(let i = 1; i <= 5; i++) {
setTimeout(function(){
console.log(i);
},100);
}
在 ES5 中,这将是一个本质上等价的结构。如果你真的研究了这个,它可以为你上面的 ES6 代码中实际发生的事情提供非常丰富的信息:
(function() {
for (var i = 1; i <= 5; i++) {
i = (function(j) {
setTimeout(function(){
console.log(j);
},100);
return j;
})(i);
}
})();
它需要两个 IIFE(立即调用的函数表达式)来模拟这一点。外层隔离
var i
这样它就不会从 for
中泄漏出来循环和内部循环为 for
的每次调用提供单独的范围和单独的变量环形。 return j
和 i = (function(j) {...})(i)
是显示循环的下一次迭代如何受到对循环变量的修改的影响。希望这能说明
let
的有用性。适用于 for
ES6 中的循环以及当您需要/想要此功能时它替换了多少其他代码。现在针对您的具体问题
For this, I have read explanations over the Internet like - let creates a variable declaration for each loop which is block level declaration. So basically it creates a scope within { }
let
定义具有 block 作用域的变量(不是函数作用域,如 var
)。而且,{
和 }
描绘for
循环确实定义了一个范围。Also, variable i is declared, initialized and incremented outside the loop block i.e. curly braces in the for loop statement.
嗯,不完全是。
for
循环是如何初始化第一个 i
的指令为第一次调用循环创建。事实上,let i = 1
出现在循环之外确实看起来有点困惑,但它实际上只是一个关于创建第一个 i
时要做什么的说明。第一次调用循环的变量。那第一个i
变量实际上并不存在于循环范围之外。So, in each iteration isn’t the same variable i is incremented and utilized?
不会。当 ES6 遇到
for
时使用 let
循环定义,它为循环的每次迭代创建一个新变量。How exactly does let creates a variable declaration for each loop and has value of previous iteration?
不是
let
这样做。这是for
ES6+ JS 解释器中的循环逻辑。这是 for
的特殊行为。具有用 let
声明的索引初始化程序的循环.所以,这是 let
的组合行为和 for
,但真正的逻辑是for
循环由解释器执行。修改循环变量时的特殊情况
let
还有一个特例在 for
循环。如果您分配给 i
的值在循环中,它将更改 i
的特定值它还会影响下一次迭代的值i
.这有点特殊,但它仍然允许您操纵 i
的值。在循环。for(let i = 1; i <= 5; i++) {
let j = i;
setTimeout(function(){
console.log(j);
},100);
if (i === 2) {
i++; // bump the loop increment to skip the 3 value
}
}
这将创建输出:
1
2
4
5
所以,这会跳过
3
循环的迭代,因为当 i === 2
,我们将它增加到 3,然后 for
循环执行其i++
迭代并将其提升到 4
,有效地跳过 3
迭代。
关于JavaScript:理解 for 循环中的 let 范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59170277/