我知道 let
可以防止重复声明,这很好。
let x;
let x; // error!
用let
声明的变量也可以用在可以预期的闭包中
let i = 100;
setTimeout(function () { console.log(i) }, i); // '100' after 100 ms
我有点难以理解的是 let
如何应用于循环。这似乎特定于 for
循环。考虑经典问题:
// 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
有效?在我的想象中,即使只有一个 block 是可见的,for
实际上为每次迭代创建一个单独的 block ,并且 let
声明是在该 block 内完成的......但是有只有一个 let
声明来初始化值。这只是 ES6 的语法糖吗?这是如何工作的?
我了解 var
和 let
之间的区别,并在上面进行了说明。我特别想了解为什么使用 for
循环时不同的声明会导致不同的输出。
最佳答案
Is this just syntactic sugar for ES6?
不,它不仅仅是语法糖。血淋淋的细节隐藏在 §13.6.3.9
CreatePerIterationEnvironment
中.
How is this working?
如果你使用那个 let
for
中的关键字语句,它将检查它绑定(bind)的名称,然后
- 使用这些名称为 a) 初始化表达式 b) 每次迭代创建一个新的词法环境(之前评估增量表达式)
- 将具有这些名称的所有变量的值从一个环境复制到下一个环境
你的循环语句 for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
脱糖到一个简单的
// 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++;
…
同时 for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
对更复杂的情况进行“脱糖”
// 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++;
…
关于javascript - `let` 的解释和带有 for 循环的 block 作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30899612/