使用 for 循环解释 `let` 和块作用域 [英] Explanation of `let` and block scoping with for loops
问题描述
我知道 let
可以防止重复声明,这很好.
I understand that let
prevents duplicate declarations which is nice.
let x;
let x; // error!
用 let
声明的变量也可以用在可以预期的闭包中
Variables declared with let
can also be used in closures which can be expected
let i = 100;
setTimeout(function () { console.log(i) }, i); // '100' after 100 ms
我有点难以理解的是 let
如何应用于循环.这似乎特定于 for
循环.考虑经典问题:
What I have a bit of difficulty grasping is how let
applies to loops. This seems to be specific to for
loops. Consider the classic problem:
// prints '10' 10 times
for (var i = 0; i < 10; i++) { process.nextTick(_ => console.log(i)) }
// prints '0' through '9'
for (let i = 0; i < 10; i++) { process.nextTick(_ => console.log(i)) }
为什么在这种情况下使用 let
有效?在我的想象中,即使只有一个块是可见的,for
实际上为每次迭代创建了一个单独的块,并且 let
声明是在该块内完成的......但是有只有一个 let
声明来初始化值.这只是 ES6 的语法糖吗?这是如何工作的?
Why does using let
in this context work? In my imagination even though only one block is visible, for
actually creates a separate block for each iteration and the let
declaration is done inside of that block ... but there is only one let
declaration to initialize the value. Is this just syntactic sugar for ES6? How is this working?
我了解 var
和 let
之间的区别,并在上面进行了说明.我特别想了解为什么使用 for
循环时不同的声明会导致不同的输出.
I understand the differences between var
and let
and have illustrated them above. I'm particularly interested in understanding why the different declarations result in different output using a for
loop.
推荐答案
这只是 ES6 的语法糖吗?
Is this just syntactic sugar for ES6?
不,它不仅仅是语法糖.血腥的细节隐藏在 §13.6.3.9CreatePerIterationEnvironment
.
No, it's more than syntactic sugar. The gory details are buried in §13.6.3.9
CreatePerIterationEnvironment
.
这是如何工作的?
如果您在 for
语句中使用该 let
关键字,它会检查绑定的名称,然后
If you use that let
keyword in the for
statement, it will check what names it does bind and then
- 使用这些名称创建一个新的词法环境 a) 初始化表达式 b) 每次迭代(之前评估增量表达式)
- 将具有这些名称的所有变量的值从一个环境复制到下一个环境
你的循环语句 for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
desugars to a simple
Your loop statement for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
desugars to a simple
// omitting braces when they don't introduce a block
var i;
i = 0;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
…
while for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
对更复杂的情况进行脱糖"
while for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
does "desugar" to the much more complicated
// using braces to explicitly denote block scopes,
// using indentation for control flow
{ let i;
i = 0;
__status = {i};
}
{ let {i} = __status;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
…
这篇关于使用 for 循环解释 `let` 和块作用域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!