为什么在try/catch中重新声明一个参数会抛出一个ReferenceError?

rle*_*mon 31 javascript

我错误地将一个论证的重新声明写成了const一个函数,而不是抛出SyntaxError: Identifier 'bar' has already been declared我最终的结果ReferenceError: bar is not defined..

是什么导致这种行为?这不是预期的错误,让我困惑了几分钟.

示例代码:

function foo(bar) {
  try {
      console.log(bar);
      const bar = 123;
  } catch(err) { console.log(err) }
}
foo(456);
Run Code Online (Sandbox Code Playgroud)

如果我没有在try/catch中包装声明,我得到(我相信是)预期的错误.

Mar*_*ons 19

常量是块范围的,非常类似于使用let语句定义的变量.

来自这篇MDN文章.

由于您bar在一个大括号内包装,因此它的定义与该块相关.并且因为bar在该块内部有另一个声明,尽管在调用它之后,编译器将尝试使用这个新定义的bar而不是传入的参数.将它们重命名为单独的参数以减轻混淆,因为可以假设它们由于您的声明而持有不同的数据.


Cer*_*rus 8

因为const声明是块作用域的,所以const bar声明会被提升到块的开头.(就在之后try {)

这意味着当您尝试记录它时bar实际上并未定义,因为提升会覆盖/隐藏参数bar.


T.J*_*der 8

这是一个神话,const而且let根本没有悬挂.他们 ho .. :-)即:在一个块内,如果const barlet bar(或者class bar { }就此而言)出现在该块中的任何地方,则bar不能在块中的该声明之前使用 - 即使它存在于包含范围内.块的开头和声明之间的区域称为Temporal Dead Zone:

function foo(bar) {
  // `bar` is fine here
  try {
      // Temporal Dead Zone, `bar` cannot be used here
      console.log(bar);
      // End of TDZ
      const bar = 123;
      // `bar` would be fine here
  } catch(err) { console.log(err) }
}
foo(456);    
Run Code Online (Sandbox Code Playgroud)