当为“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 在 <script>
标签内运行,如果发生这样的错误,通常没有更多的代码将运行,而使用 let
声明的变量不再可重新分配这一事实是您最不必担心的。
以上是早期 Chrome 版本中的问题。但是in Chrome 80+,现在允许重新声明let
,所以the error
未捕获的 SyntaxError:标识符“withLet”已被声明
应该不再发生,无论之前的变量初始化是否成功:
【讨论】:
只是为了扩展一点 - 一个变量需要三个阶段才能变为“真实”。声明(该标识符存在)、初始化(该标识符处于活动状态且可以使用)、赋值(该标识符有一个值)。对于var
,声明+初始化被提升。对于 let
/const
,只有 声明 被提升,初始化 稍后出现 - 如上所述,当到达 let myVar
行时。以上是关于当为“var”和“let”分配一个引发错误的函数的返回值时,是啥导致了它们之间的不同行为的主要内容,如果未能解决你的问题,请参考以下文章