繁体   English   中英

双重声明:如何让吊装在循环中工作?

[英]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 declaredIdentifier '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循环标题中开始,另一个在用{}包围的块中开始。

下面发生的是JavaScript在同一个for循环中看到两个不同级别的块范围。

第一个是在循环的初始化子句( let i = 0; )中声明循环内部的第二个。

这是第一次运行代码时发生的情况:

  • let 初始化子句i = 0 ;
  • let for-loop 内部i is set to undefined

在此输入图像描述

当for循环命中console.log(i)它在循环中找到let i的声明,它覆盖先前声明的并分配了let i (在初始化子句中)。

由于每次提升, letconst被声明但未初始化( undefined ),它会抛出一个ReferenceError。

累计到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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM