是什么导致 "var" 和 "let" 在为它们分配抛出错误的函数的返回值时出现不同的行为

What causes the different behaviors between "var" and "let" when assign them a returned value of a function which throws an error

请在下图中找到代码。 1. 将实际抛出错误的函数的返回值赋值给使用关键字'let'声明的变量'withLet'。 2.调用'withLet',出现错误:'withLet is not defined'。 3.尝试使用'let'断言'withLet',报错显示'withLet'已经声明

但是'var'不存在悖论(请看下图)

我很好奇是什么导致了这两种情况之间的不同行为。 'not defined' 和 'already been declared' 描述了相同的变量,这很有趣。

let withLet = (function() {throw 'error!'})()
var withVar = (function() {throw 'error!'})()
//VM2470:1 Uncaught error!
//(anonymous) @ VM2470:1
//(anonymous) @ VM2470:1
withLet
//VM2484:1 Uncaught ReferenceError: withLet is not defined at 
//<anonymous>:1:1
//(anonymous) @ VM2484:1
withVar
//undefined
let withLet = 'sth'
//VM2520:1 Uncaught SyntaxError: Identifier 'withLet' has already been 
//declared
//at <anonymous>:1:1
//(anonymous) @ VM2520:1
withVar = 'sth'
//"sth"

截图:

var 变量的声明被提升 - 变量名初始化被提升到包含函数的顶部(或者,如果没有函数,则提升到外部块的顶部)。所以

var withVar = (function() {throw 'error!'})()

被解释器解析为

var withVar;
withVar = (function() {throw 'error!'})()

let 情况并非如此 - let 变量在 let __ 行 运行 后被初始化。有赋值时,先解析右边;如果右侧抛出错误,它永远不会到达左侧,并且用 let 声明的变量永远不会被正确初始化;它会永远留在 demilitarized zone / temporal dead zone 中,因此尝试重新分配它会引发错误。

这有点奇怪,因为代码在 控制台 中被 运行 - 通常,JS 运行s 在 <script> 标签中, 如果发生这样的错误,通常 不再有代码 运行,并且用 let 声明的变量不再可重新分配这一事实是最不重要的你的烦恼。


以上是早期 Chrome 版本中的问题。但是 in Chrome 80+, re-declarations of let are now permitted, so the error

Uncaught SyntaxError: Identifier 'withLet' has already been declared

应该不会再出现了,不管之前的变量初始化是否成功: