Переменная не может быть объявлена или изменена
У меня есть вопрос по поводу 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 как config в конструктор.
РЕДАКТИРОВАТЬ: я также пытался использовать var, я могу использовать myClassInstance. Интересно, почему, если я использую let, эта переменная не может быть удалена, объявлена или новое значение не может быть переназначено.
РЕДАКТИРОВАТЬ 2: я могу обработать передачу неопределенного или передать пустой объект. Просто любопытство, что происходит в консоли JS с этой переменной, также код не будет выполняться, если вы вставите все сразу
2 ответа
Запуск кода в интерактивной консоли создает сложную ситуацию, которая не может произойти при обычном выполнении кода.
Во-первых, то, что вы видите, не относится только к ошибкам, генерируемым в конструкторах классов. Вы можете наблюдать такое же поведение, если вы выполните любое let
утверждение, где RHS выдает ошибку:
let myVariable = "".boom();
Документация по MDN говорит о "временной мертвой зоне", где переменная, объявленная с let
существует, но рассматривается как не существующий до let
Заявление успешно выполнено.
Из спецификации ES6:
Переменные создаются, когда создается экземпляр их содержащей Lexical Environment, но к ним нельзя получить доступ, пока не будет оценена переменная LexicalBinding.
Проще говоря, переменная была создана, но к ней нельзя получить доступ, поскольку ее "LexicalBinding" не был оценен.
Используя консоль, вы создали ситуацию, когда:
let
Оператор не был успешно выполнен (поэтому этоReferenceError
попытаться получить доступ к его переменной).- У вас есть два
let
s для одного и того же имени переменной в той же области видимости (поэтому вторая создает синтаксическую ошибку). (нб просто имея дваlet
s в той же области действия может привести к сбою кода на этапе компиляции, прежде чем первый даже сможет попытаться выполнить, если вы не вводите немного кода за раз в консоль).
Это ситуация, которая не может возникнуть в обычном коде.
Обычно вы не сможете продолжить выполнение операторов в области, в которой возникла ошибка, поэтому первый пункт будет невозможен. Консоль позволяет вам это сделать.
В обычных условиях это было бы невозможно в дальнейшем, потому что код потерпел бы неудачу на этапе компиляции перед первым let
Заявление может даже попытаться запустить.
Вот почему вы получаете ошибку в обоих случаях.
Хорошо, этот вопрос на самом деле очень интересный, и я, возможно, нашел ответ на него.
Явление, которое вы описываете, скорее всего, связано с тем, как движок Javascript компилирует ваш код. Хотя программисту может показаться иначе, компиляция состоит из нескольких этапов и выполняется на разных этапах процесса. Таким образом, в зависимости от того, какую ошибку вы имеете в своем коде, этот процесс может завершиться в любой точке процесса.
Итак, если создание вашего объекта имеет недостатки (config
не определено), но синтаксис сам по себе хорош (с точки зрения языка), позже вы получите ошибку в процессе компиляции по сравнению с чем-то недопустимым в Javascript в целом.
Увидеть, let
довольно сложный, потому что он предотвращает конфликты имен переменных (следовательно, Indentifier 'myClassInstance' has already been defined
ошибка). Это непохоже var
который не имеет этой функции.
Из документации MDN:
Повторное выделение одной и той же переменной в пределах одной и той же функции или области блока вызывает SyntaxError.
if (x) { let foo; let foo; // SyntaxError thrown. }
В ECMAScript 2015, let поднимет переменную в верхнюю часть блока. Однако ссылка на переменную в блоке до объявления переменной приводит к ReferenceError. Переменная находится в "временной мертвой зоне" от начала блока до обработки объявления.
TL; DR
Следующий код вызовет ошибку ранее во время процесса компиляции
let myClassInstance = new MyClass();
let myClassInstance = '123';
по сравнению с:
let myClassInstance = new MyClass();
myClassInstance = '123';
Это потому, что первый является недопустимым синтаксисом в Javascript, а второй - нет. В последнем случае код будет хорошо скомпилирован, но потерпит неудачу во время выполнения, поскольку аргумент не определен.
РЕДАКТИРОВАТЬ:
Я нашел этот блог и довольно интересно читать. Snippet:
А? Проще говоря, этот движок JavaScript берет ваш исходный код, разбивает его на строки (он же лексизирует его), берет эти строки и преобразует их в байт-код, понятный компилятору, а затем выполняет его.
Еще один урок глубокого погружения здесь.