双 let 声明:let 提升如何在 for 循环中工作?
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
而不是 Identifier 'i' has already been declared
.
JS如何读取上面的代码?
根据 MDN:
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
Due to lexical scoping, the identifier "foo" inside the expression (foo + 55) evaluates to the if block's foo, and not the overlying variable foo with the value of 33.
In that very line, the if block's "foo" has already been created in the lexical environment, but has not yet reached (and terminated) its initialization (which is part of the statement itself): it's still in the temporal dead zone.
这意味着如果循环变量在你的例子中是 "read",(console.log 在你的例子中,你不能将它分配给同名的 var,因为它在 "dead zone"
MDN 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let(在临时死区下)
let
variables should be hoisted as all other types of the declaration.
let
变量 未 提升,这与 var
变量和函数以及 class 声明不同。 const
变量相同
直到您到达声明它的行,该变量才开始存在。
但是,在到达声明之前,您无法访问相关范围内的变量。这有点无益,被称为时间死区。 (Useful 2ality blog)
这很有用,因为在变量声明之前访问它几乎总是错误的。或者,至少,它会在您重构时造成混淆并导致错误。
function foo(n){
for (let i = 0; i < n; i++) {
// i cannot be accessed
let i = 10;
// i is set to 10
}
}
foo(4);
至于为什么不是"identifier already declared"错误,在for
循环header中声明的变量范围是一个独立于块中声明的变量.这段代码中基本上有三个作用域:外部作用域,在 for
循环 header 中开始的作用域,以及在 {}
.
包围的块中开始的作用域
下面发生的事情是 JavaScript 在同一个 for 循环中看到两个不同级别的块作用域。
第一个在循环的初始化子句中声明 (let i = 0;
),第二个在循环本身内声明。
这是您第一次 运行 代码时发生的情况:
let
在 初始化子句中 : i = 0
;
let
在 for 循环中:i is set to undefined
当 for 循环遇到 console.log(i)
时,它会在循环内找到 let i
的声明,该声明会覆盖先前声明和赋值的 let i
(在初始化子句中。
由于每次提升,let
和 const
被声明但未初始化(如 undefined
),它会抛出 ReferenceError。
给定以下简化代码,为什么会出现 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
而不是 Identifier 'i' has already been declared
.
JS如何读取上面的代码?
根据 MDN:
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
Due to lexical scoping, the identifier "foo" inside the expression (foo + 55) evaluates to the if block's foo, and not the overlying variable foo with the value of 33. In that very line, the if block's "foo" has already been created in the lexical environment, but has not yet reached (and terminated) its initialization (which is part of the statement itself): it's still in the temporal dead zone.
这意味着如果循环变量在你的例子中是 "read",(console.log 在你的例子中,你不能将它分配给同名的 var,因为它在 "dead zone"
MDN 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let(在临时死区下)
let
variables should be hoisted as all other types of the declaration.
let
变量 未 提升,这与 var
变量和函数以及 class 声明不同。 const
变量相同
直到您到达声明它的行,该变量才开始存在。
但是,在到达声明之前,您无法访问相关范围内的变量。这有点无益,被称为时间死区。 (Useful 2ality blog)
这很有用,因为在变量声明之前访问它几乎总是错误的。或者,至少,它会在您重构时造成混淆并导致错误。
function foo(n){
for (let i = 0; i < n; i++) {
// i cannot be accessed
let i = 10;
// i is set to 10
}
}
foo(4);
至于为什么不是"identifier already declared"错误,在for
循环header中声明的变量范围是一个独立于块中声明的变量.这段代码中基本上有三个作用域:外部作用域,在 for
循环 header 中开始的作用域,以及在 {}
.
下面发生的事情是 JavaScript 在同一个 for 循环中看到两个不同级别的块作用域。
第一个在循环的初始化子句中声明 (let i = 0;
),第二个在循环本身内声明。
这是您第一次 运行 代码时发生的情况:
let
在 初始化子句中 :i = 0
;let
在 for 循环中:i is set to undefined
当 for 循环遇到 console.log(i)
时,它会在循环内找到 let i
的声明,该声明会覆盖先前声明和赋值的 let i
(在初始化子句中。
由于每次提升,let
和 const
被声明但未初始化(如 undefined
),它会抛出 ReferenceError。