[英]Double let declaration: How does let hoisting work in for loops?
鉴于以下简化代码,为什么我会得到一个ReferenceError?
function foo(n){
for (let i = 0; i < n; i++) {
console.log(i);
let i = 10;
}
}
foo(4);
// OUTPUT: ReferenceError: i is not defined
let
变量应该像所有其他类型的声明一样被提升。 因此,在此代码中, i
被声明两次。 首先,在初始化关闭和第二个for循环本身。
为什么i is not defined
此输出i is not defined
而不是Identifier 'i' has already been declared
了Identifier 'i' has already been declared
。
JS如何阅读上面的代码?
let
变量应该像所有其他类型的声明一样被提升。
let
变量没有悬挂,不同var
变量和函数和类的声明。 const
变量是相同的。
变量在到达声明它的行之前不会存在。
但是 ,在到达声明之前,您无法访问相关范围中的变量。 这有点无益,被称为时间死区 。 ( 有用的2ality博客 )
这很有用,因为在声明变量之前访问它几乎总是一个错误。 或者,至少,它是令人困惑的,并会在您重构时导致错误。
function foo(n){
for (let i = 0; i < n; i++) {
// i cannot be accessed
let i = 10;
// i is set to 10
}
}
foo(4);
至于为什么它不是“已经声明的标识符”错误, for
循环标头中声明的变量的范围是与块中声明的变量的单独变量。 这段代码中基本上有三个范围:外部的一个,一个在for
循环标题中开始,另一个在用{}
包围的块中开始。
累计到MDN:
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
由于词法作用域,表达式(foo + 55)中的标识符“foo”评估为if块的foo,而不是值为33的上覆变量foo。在那一行中,if块的“foo”已经已经在词法环境中创建,但尚未达到(并终止)其初始化(这是语句本身的一部分):它仍然处于时间死区。
这意味着如果循环变量在您的示例中是“读取”,(在您的情况下是console.log,您无法将其分配给同名的var,就像在“死区”中一样)
MDN ref: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let (在临时死区下 )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.