Почему повторное объявление аргумента внутри try/catch бросает ReferenceError?
Я ошибочно написал повторное объявление аргумента как 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, я получу (что я считаю) ожидаемой ошибкой.
Ответы
Ответ 1
Константы являются блочными, как и переменные, определенные с помощью оператора let.
Из эта статья MDN.
Поскольку вы завернули bar
внутри блока фигурных скобок, его определение относится к этому блоку. И поскольку у вас есть другое объявление bar
внутри этого блока, несмотря на то, что после вызова к нему компилятор попытается использовать этот новый bar
вместо параметра переданного. Переименуйте их как отдельные параметры для уменьшения путаницы, поскольку можно предположить, что они содержат разные данные из-за вашего объявления.
Ответ 2
Так как объявления const
являются блочными областями, объявление const bar
получает начало к началу блока. (Только после try {
)
Это означает, что bar
на самом деле не определяется при попытке зарегистрировать его, поскольку подъем поднимает/скрывает параметр bar
.
Ответ 3
Это миф о том, что const
и let
вообще не поднимаются. Они наполовину.:-) То есть: внутри блока, если const bar
или let 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);
Ответ 4
Взято отсюда https://tylermcginnis.com/videos/var-let-const/
var - это область действия, и если вы пытаетесь использовать переменную, объявленную с помощью var перед фактическим объявлением, вы просто получите undefined. Const и пусть блокируются в скобках, и если вы пытаетесь использовать const или let переменная перед объявлением вы получите опорную ошибку.