声明变量和定义变量有什么区别吗?

8
我试着在控制台逐行输入以下内容。
let x = y //throws error "Uncaught ReferenceError: y is not defined"
console.log(x) //throws error "ReferenceError: x is not defined"
let x = 3; //gives error "Uncaught SyntaxError: Identifier 'x' has already been declared"
x = 3 //ReferenceError: x is not defined

现在的问题是,一个变量如何能够同时被未定义已声明。这两者有什么区别吗?


3
浏览器控制台使用语言不当。那些“ReferenceError”应该真正表明该变量没有被“声明”,但据我所知它一直是这样的。 - Robin Zigmond
3
当有赋值语句时,右侧先被解析;如果右侧抛出错误,则不会执行左侧,并且使用 let 声明的变量将无法被正确初始化。它将永远停留在未初始化区域 / 暂时性死区中 (即使在初始化期间尝试赋值时发生错误,也不能重新声明已经声明过的变量)。 - CertainPerformance
@cнŝdk 但是 console.log(x) 抛出了一个错误 x未定义 - Maheer Ali
1
@MaheerAli 如果你已经声明了 let x = 3;,那么它会抛出错误。但是 x=3 不应该抛出错误,除非你将其定义为 const - Rajesh
1
被声明并不意味着它将被初始化为未定义。在ES6中,使用let或const声明的变量是否不会被提升? - adiga
显示剩余5条评论
1个回答

7

letconst变量只能在声明一次,也就是说,当你在作用域中使用let <variableName>声明变量时,在该作用域中已经声明了<variableName>,不能再在该作用域中重新声明。

来自之前链接的问题:

有赋值时,先解析右侧内容;如果右侧内容抛出错误,则不会到达左侧内容,并且使用 let 声明的变量永远无法正确初始化;它将永远停留在未武装区/时间死区中。

即使在初始化期间尝试分配失败,也不能重新声明已经声明过的变量。

但是,在第4行,x=3 应该进行适当的赋值,然后应该从 TDZ 中删除 x。但这也失败了。我不明白为什么

在变量被初始化(例如,运行let x)之后,可以对其进行赋值。但是,就像您不能在其let初始化之前对变量进行赋值一样,如果变量的初始化没有成功完成,则以后也不能对其进行赋值:

x = 'foo';
let x = 'bar';

错误:

未捕获的引用错误:x未定义

这和在控制台中尝试以下操作时发生的情况类似:

let x = y
// Uncaught ReferenceError: y is not defined
// x has not been initialized, so the next line throws:
x = 'foo'
// Uncaught ReferenceError: x is not defined

x 仍未初始化,因此错误仍然存在。

遇到这种情况很奇怪 - 只有在控制台中才能看到。在正常的脚本中,抛出的错误将阻止进一步执行,变量名永远不会初始化也不是什么值得担心的事情。


以上是早期 Chrome 版本中的问题。但是在 Chrome 80+ 中,现在允许重新声明 let,因此无论之前变量的初始化是否成功,错误

Uncaught SyntaxError: Identifier 'x' has already been declared

不应再发生,不管之前的变量是否已经初始化:

enter image description here


1
我想指出,在Firefox的控制台中,let x = y确实会初始化x,而x = "foo"不会抛出异常。然而,在控制台之外执行相同的操作时,它会正确地抛出异常。 - Kaiido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接