所以我的代码中有一个x is not defined
错误,这让我有点困惑,因为x
以前已经定义了几行。我不得不花一些时间调整我的代码,删除和添加行,直到我设法理解为什么会发生这种情况。在我删除了所有不必要的信息后,现在代码看起来是这样的:
let foo = 2;
console.log(foo);
if (foo === 2){
console.log(foo);
let foo = 1;
}
它在第5行抛出foo is not defined
。当我尝试console.log(foo)
时,会弹出一个错误!如果我删除第6行let foo = 1;
,代码就可以正常工作。我的意思是,在我第二次声明foo
之前会发生错误。所以第一个问题是:
- 第6行(尚未执行(怎么可能导致第5行出现错误
我不明白的第二件事是为什么它说的是foo is not defined
而不是foo has been already declared
。如果我用var
替换第二个let
,第6行将出现一个错误,它会说foo has been already declared
,所以看起来很好。但是,将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
。
除了作用域之外,这个TDZ是var
和let
之间的最大区别,var
创建了一个绑定,并且将其初始化为undefined
,而不管var
语句在作用域中的什么位置。相反,let
(以及const
和class
(创建绑定,但直到稍后在代码的逐步执行中遇到let
(const
、class
(时才初始化它。不能使用未初始化的绑定。
- 为什么会抛出错误
这没有错。你可以说它措辞拙劣基本上,它是在说"你不能在这里使用foo
,它没有初始化。"在我看来,来自V8(Chrome、Chromium、Brave、新的基于Chromium的Edge和Node.js中的JavaScript引擎(的当前错误消息更清楚:
未捕获引用错误:在初始化之前无法访问"foo">
使用let
声明变量时,该变量在当前代码块的范围内有效。第二个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
,那么您应该在使用之前将其定义移动到。
注意,使用var
具有不同的结果,因为var
变量的范围比let
变量的范围宽。见这里有这个定义:
let允许您声明限制在block语句或使用它的表达式,与var不同关键字,它全局地或局部地定义一个变量函数,而与块范围无关。
为了让它更清楚,我用代码每个阶段的变量状态标记了您的代码:
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