Переменная не может быть объявлена или изменена
У меня вопрос о JavaScript. Когда я объявляю новую переменную и назначаю ей новый экземпляр класса, если ошибка выбрана, переменная становится полностью непригодной.
Код ниже должен вызывать ошибку
class MyClass {
constructor (config) {
this.someProperty = config.someProperty || '';
}
}
let myClassInstance = new MyClass();
Если я попытаюсь присвоить ему что-то, JavaScript будет вызывать ошибку.
myClassInstance = '123'
Uncaught ReferenceError: myClassInstance не определен
Затем я попытался определить переменную
let myClassInstance = '123'
Uncaught SyntaxError: идентификатор 'myClassInstance' уже объявлен
Переменная также не может быть удалена. Есть ли что-то, что мы можем сделать с этой проблемой? Мне просто интересно, конечно, я обработаю передачу undefined как конфигурацию для конструктора.
EDIT: Я также попытался использовать var, я могу повторно использовать myClassInstance. Интересно, почему, если я использую, пусть эта переменная не может быть удалена, декларативное или новое значение не может быть переназначено.
EDIT 2: Я могу обрабатывать передачу undefined или передавать пустой объект. Просто чистое любопытство, что происходит в консоли JS с этой переменной, также код не будет выполняться, если вы вставляете все сразу
Ответы
Ответ 1
Запуск кода в интерактивной консоли создает надуманную ситуацию, которая не может произойти при типичном выполнении кода.
Во-первых, то, что вы видите, не относится к ошибкам, возникающим в конструкторах классов. Вы можете наблюдать такое же поведение, если вы выполняете оператор let
, где RHS выдает ошибку:
let myVariable = "".boom();
Документация в MDN говорит о "временной мертвой зоне", где существует переменная, объявленная с помощью let
, но рассматривается как не существующая пока оператор let
не будет успешно выполнен.
Из спецификации ES6:
Переменные создаются, когда их содержащая Лексическая среда создается, но может быть недоступна каким-либо образом, пока не будут оценены переменные LexicalBinding.
Простыми словами, переменная была создана, но недоступна, поскольку ее "Лексическая привязка" не была оценена.
Используя консоль, вы создали ситуацию, в которой:
- Оператор
let
не был успешно выполнен (так что ReferenceError
пытается получить доступ к своей переменной).
- У вас есть два
let
для одного и того же имени переменной в пределах одной области (поэтому вторая создает синтаксическую ошибку). (nb Просто наличие двух let
в том же объеме приведет к сбою кода на этапе компиляции, прежде чем первый из них даже попытается выполнить, если вы не вводили код немного за раз в консоль).
Это ситуация, которая не может произойти в обычном коде.
Как правило, вы не сможете продолжать выполнение операторов в области, где была вызвана ошибка, поэтому первая пуля была бы невозможна. Консоль позволяет это сделать.
В обычных обстоятельствах это было бы невозможно, потому что код завершился неудачно на этапе компиляции, прежде чем первый оператор let
мог даже попытаться запустить.
Итак, почему вы получаете ошибку в обоих случаях.
Ответ 2
Хорошо, этот вопрос действительно интересен, и я, возможно, нашел для него ответ.
Явление, которое вы описываете, скорее всего связано с тем, как механизм Javascript компилирует ваш код. Хотя программисту может показаться иначе, компиляция состоит из нескольких этапов и выполняется на разных этапах процесса. Таким образом, в зависимости от того, какая у вас ошибка в коде, этот процесс может завершиться в любой момент процесса.
Итак, если ваше создание объекта ошибочно (config
is undefined), но синтаксис сам по себе является прекрасным (с точки зрения языка), вы получите ошибку позже в процессе компиляции по сравнению с чем-то, что незаконно в Javascript вообще.
См., let
довольно сложный, поскольку он предотвращает столкновение имен имен (следовательно, ошибка Indentifier 'myClassInstance' has already been defined
). Это не похоже на var
, у которого нет этой функции.
Из Документация MDN:
Повторное использование одной и той же переменной в той же функции или области блока вызывает синтаксический эффект.
if (x) {
let foo;
let foo; // SyntaxError thrown.
}
В ECMAScript 2015 давайте поднимите переменную до вершины блок. Однако, ссылаясь на переменную в блоке до объявление переменной приводит к использованию ReferenceError. Переменная находится в "временная мертвая зона" от начала блока до объявления обрабатывается.
TL; DR
Следующий код вызовет ошибку ранее во время процесса компиляции
let myClassInstance = new MyClass();
let myClassInstance = '123';
по сравнению с:
let myClassInstance = new MyClass();
myClassInstance = '123';
Это потому, что первый является незаконным синтаксисом в Javascript, а второй - нет. В последнем случае код будет компилироваться отлично, но не будет работать во время выполнения, потому что аргумент undefined.
EDIT:
Я нашел этот блог и довольно интересный текст. Отрывок:
А? Проще говоря, этот механизм JavaScript принимает ваш исходный код, разбивает его на строки (a.k.a. lexes it), берет эти строки и преобразует их в байт-код, который компилятор может понять, а затем выполняет его.
Другой учебник по глубокому погружению здесь.