当为“var”和“let”分配一个引发错误的函数的返回值时,是啥导致了它们之间的不同行为

Posted

技术标签:

【中文标题】当为“var”和“let”分配一个引发错误的函数的返回值时,是啥导致了它们之间的不同行为【英文标题】:What causes the different behaviors between "var" and "let" when assign them a returned value of a function which throws an error当为“var”和“let”分配一个引发错误的函数的返回值时,是什么导致了它们之间的不同行为 【发布时间】:2019-06-11 09:37:08 【问题描述】:

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

但“var”不存在悖论(请参见下图)。

我很好奇是什么导致了这两种情况之间的不同行为。 “未定义”和“已声明”描述了同一个变量,这很正常。

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"

截图:

【问题讨论】:

Firefox 只打印undefined Chrome 为每个函数调用抛出 errors! 我认为这是引擎中的错误。 withLet 应该被初始化,undefined 但由于变量范围的性质,它可能会以不同的方式处理它。 这里有重要的说明 - 这发生在 Chrome/V8 中,但不在 Firefox 中。因此,这是特定于实现的行为。 【参考方案1】:

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

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

被解释器解析为

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

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

这有点奇怪,因为代码是在 console 中运行的——通常,JS 在 &lt;script&gt; 标签内运行,如果发生这样的错误,通常没有更多的代码将运行,而使用 let 声明的变量不再可重新分配这一事实是您最不必担心的。


以上是早期 Chrome 版本中的问题。但是in Chrome 80+,现在允许重新声明let,所以the error

未捕获的 SyntaxError:标识符“withLet”已被声明

应该不再发生,无论之前的变量初始化是否成功:

【讨论】:

只是为了扩展一点 - 一个变量需要三个阶段才能变为“真实”。声明(该标识符存在)、初始化(该标识符处于活动状态且可以使用)、赋值(该标识符有一个值)。对于var,声明+初始化被提升。对于 let/const,只有 声明 被提升,初始化 稍后出现 - 如上所述,当到达 let myVar 行时。

以上是关于当为“var”和“let”分配一个引发错误的函数的返回值时,是啥导致了它们之间的不同行为的主要内容,如果未能解决你的问题,请参考以下文章

Javascript通过解构重新分配let变量[重复]

var 在异步中引发的 bug

let var 和const声明变量,之间的区别是什么

覆盖函数指针引发错误:非对象类型不可分配

js书写规范

关于 ES6 的 let ,var和 const