使用for循环的`let`和block作用域的解释 [英] Explanation of `let` and block scoping with for loops
问题描述
我明白 let
阻止重复的声明是很好的。
让x;
let x; //错误!
也可以使用用 let
声明的变量在可以预期的关闭中
let i = 100;
setTimeout(function(){console.log(i)},i); //'100'后100 ms
我有一些困难抓住是如何 let
适用于循环。这似乎是针对循环的特定的。考虑经典问题:
//打印'10'10次
(var i = 0; i< ;(i; i ++){process.nextTick(_ => console.log(i))}
//打印'0'到'9'
for(let i = 0; i& 10; i ++){process.nextTick(_ => console.log(i))}
为什么在这个上下文中使用 let
?在我的想象中,尽管只有一个块可见,为
实际上为每次迭代创建一个单独的块,并且 let
声明在该块内部完成...但是只有一个 let
声明来初始化该值。这只是ES6的语法糖吗?如何工作?
我了解 var
和 let
并在上面说明了它们。我特别有兴趣了解为什么不同的声明导致使用循环的不同的输出。
这是ES6的句法糖吗?
不,更多比语法糖。血清细节埋在§13.6.3.9
CreatePerIterationEnvironment
。
这是如何工作的? b $ b
如果您在中使用
语句,它将检查它绑定的名称,然后让
关键字
- 创建一个新的词汇环境,其名称为a)初始化器表达式b)每次迭代(以前用于评估增量表达式)
- 将所有变量的值从一个值复制到下一个环境
< )} desugars to a simple
//在不引入块时省略大括号
var i;
i = 0;
if(i< 10)
process.nextTick(_ => console.log(i))
i ++;
if(i< 10)
process.nextTick(_ => console.log(i))
i ++;
...
而 for(let i = 0; i< ; 10; i ++){process.nextTick(_ => console.log(i))}
对更复杂的
desugar $
//使用缩进控制流
{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 ++;
...
I understand that let
prevents duplicate declarations which is nice.
let x;
let x; // error!
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
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)) }
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?
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.
Is this just syntactic sugar for ES6?
No, it's more than syntactic sugar. The gory details are buried in §13.6.3.9
CreatePerIterationEnvironment
.
How is this working?
If you use that let
keyword in the for
statement, it will check what names it does bind and then
- create a new lexical environment with those names for a) the initialiser expression b) each iteration (previosly to evaluating the increment expression)
- copy the values from all variables with those names from one to the next environment
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)) }
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`和block作用域的解释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!