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

时间:2018-01-17 15:35:17

标签: 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);

如果我不在try / catch中包装声明,我会得到(我认为是)预期的错误。

4 个答案:

答案 0 :(得分:18)

  

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

来自this MDN article.

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

答案 1 :(得分:8)

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

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

答案 2 :(得分:8)

constlet根本没有被提升是一个神话。他们一半 -hoisted。 :-)即:在一个区块内,如果该区块中的任何位置出现const barlet bar(或class bar { }),则bar之前无法使用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); 块中的声明 - 即使它存在于包含范围内。块的开头和声明之间的区域称为 Temporal Dead Zone

<?= $this->Form->create('Posts', array('url' => array('controller' => 'MyController', 'action' => 'index')));?>
                        <?= $this->Form->input('title', array('type'=>'title','class'=>'form-control mr-sm-2'));?>
                        <?= $this->Form->textarea('text', array('type'=>'text','rows' => '3','class'=>'form-control'));?>
                        <?= $this->Form->submit('Posten', array('class'=>'btn btn-outline-success my-2 my-sm-0','style'=>'float:right'));?>
                    <?= $this->Form->end();?>

答案 3 :(得分:3)

从这里采取https://tylermcginnis.com/videos/var-let-const/

  

var是函数作用域,如果你尝试使用声明的变量   在实际声明之前的var,你只是得到了未定义。常量   并且如果您尝试使用const或let,则阻止作用域   在声明之前变量你将得到一个引用错误。