Javascript 最后的行(尚未执行)如何可能影响代码的开头?为什么会抛出错误呢?

Javascript 最后的行(尚未执行)如何可能影响代码的开头?为什么会抛出错误呢?,javascript,node.js,syntax-error,identifier,referenceerror,Javascript,Node.js,Syntax Error,Identifier,Referenceerror,因此,我的代码中有一个x未定义错误,这让我有点困惑,因为x之前已经定义了几行。我不得不花一些时间调整我的代码,删除和添加行,直到我设法理解它为什么会发生。在我删除了所有不必要的信息后,代码如下所示: let foo = 2; console.log(foo); if (foo === 2){ console.log(foo); let foo = 1; } 它在第5行抛出未定义的foo。当我尝试console.log(foo)时,会弹出一个错误!如果我删除第6行让foo=1代

因此,我的代码中有一个
x未定义
错误,这让我有点困惑,因为
x
之前已经定义了几行。我不得不花一些时间调整我的代码,删除和添加行,直到我设法理解它为什么会发生。在我删除了所有不必要的信息后,代码如下所示:

let foo = 2;
console.log(foo);

if (foo === 2){
    console.log(foo);
    let foo = 1;
}
它在第5行抛出未定义的
foo。当我尝试
console.log(foo)
时,会弹出一个错误!如果我删除第6行
让foo=1代码工作正常。我的意思是在我第二次声明
foo
之前发生了一个错误。因此,第一个问题是:

  • 第6行(尚未执行)如何可能导致第5行出现错误
  • 我不明白的第二件事是,为什么它说
    foo没有定义
    ,而不是
    foo已经声明了
    。 如果我用
    var
    替换第二个
    let
    ,第6行将出现一个错误,它会说
    foo已经声明了
    ,所以看起来很好。但是将
    let
    设置为第二个标识符总是会引发错误

  • 为什么会抛出不正确的错误
  • 在测试了不同的场景后,我注意到结果取决于我使用的标识符:

    identifiers |            result
    ----------------------------------------------
      var var   |      the code works well
      var let   |       not defined error
      let var   | has been already declared error
      let let   |       not defined error
    
    第三个问题是:

  • 为什么每个人都反对使用
    var
    ,而在这种情况下,双重使用
    var
    是代码完美运行的唯一方式?这是个例外吗
  • 第6行(尚未执行)如何可能导致第5行出现错误
  • 因为用
    let
    const
    class
    声明的绑定范围(松散地称为“变量”)是整个块,而不仅仅是从声明它们的位置到块的末尾。代码进入块和执行
    let
    语句之间的时间称为时间死区(TDZ),在此期间绑定存在,但未初始化,不能以任何方式使用。即使在代码流中遇到
    let foo
    之前,只要在块中使用
    let foo
    就可以对外部
    foo
    进行阴影处理

    除了作用域之外,
    var
    let
    之间的最大区别在于
    var
    创建绑定并将其初始化为
    未定义的
    ,而不管
    var
    语句在作用域中的何处。相反,
    let
    (和
    const
    class
    )创建绑定,但在以后的代码逐步执行过程中遇到
    let
    const
    class
    )时才对其进行初始化。不能使用未初始化的绑定

  • 为什么会抛出不正确的错误
  • 这是正确的。你可能会说它措词不当。:-)基本上,它说“你不能在这里使用
    foo
    ,它没有初始化。”在我看来,V8(Chrome、Chrome、Brave、新的基于Chrome的Edge和Node.js中的JavaScript引擎)当前的错误消息更清楚:

    未捕获引用错误:在初始化之前无法访问“foo”

  • 第6行(尚未执行)如何可能导致第5行出现错误
  • 因为用
    let
    const
    class
    声明的绑定范围(松散地称为“变量”)是整个块,而不仅仅是从声明它们的位置到块的末尾。代码进入块和执行
    let
    语句之间的时间称为时间死区(TDZ),在此期间绑定存在,但未初始化,不能以任何方式使用。即使在代码流中遇到
    let foo
    之前,只要在块中使用
    let foo
    就可以对外部
    foo
    进行阴影处理

    除了作用域之外,
    var
    let
    之间的最大区别在于
    var
    创建绑定并将其初始化为
    未定义的
    ,而不管
    var
    语句在作用域中的何处。相反,
    let
    (和
    const
    class
    )创建绑定,但在以后的代码逐步执行过程中遇到
    let
    const
    class
    )时才对其进行初始化。不能使用未初始化的绑定

  • 为什么会抛出不正确的错误
  • 这是正确的。你可能会说它措词不当。:-)基本上,它说“你不能在这里使用
    foo
    ,它没有初始化。”在我看来,V8(Chrome、Chrome、Brave、新的基于Chrome的Edge和Node.js中的JavaScript引擎)当前的错误消息更清楚:

    未捕获引用错误:在初始化之前无法访问“foo”


    使用
    声明变量时,让它在当前代码块的范围内有效。您的第二个
    let foo
    声明定义了一个独立于第一个变量的
    foo
    ,它仅在if块中有效。但是,您在定义它之前使用它,因此您可以正确地获得尚未定义的错误

    如果您真的希望有两个不同的
    foo
    变量,我建议您将它们称为其他变量(例如foo1和foo2),以避免冲突。然后很明显,在定义变量之前,您正在使用该变量

    let foo1 = 2;
    console.log(foo1);
    
    if (foo1 === 2){
        console.log(foo1);
        let foo2 = 1;
    }
    
    如果您的意思是第5行使用设置为2的
    foo
    的第一个实例,那么您已经通过If代码块中出现的新定义将其隐藏

    如果您的意思是在第5行中使用设置为1的
    foo
    ,则应在使用之前将其定义移动到

    let foo = 2;          // foo defined and set to 2
    console.log(foo);     // foo defined and set to 2
    
    if (foo === 2)        // foo defined and set to 2
    {                     // <-- start of the if-block!
        console.log(foo); // foo not defined yet
        let foo = 1;      // foo defined and set to 1
    }                     // <-- end of if-block!
    console.log(foo);     // foo defined and set to 2