Переменная не может быть объявлена ​​или изменена

У меня есть вопрос по поводу 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 попытаться получить доступ к его переменной).
  • У вас есть два lets для одного и того же имени переменной в той же области видимости (поэтому вторая создает синтаксическую ошибку). (нб просто имея два lets в той же области действия может привести к сбою кода на этапе компиляции, прежде чем первый даже сможет попытаться выполнить, если вы не вводите немного кода за раз в консоль).

Это ситуация, которая не может возникнуть в обычном коде.

Обычно вы не сможете продолжить выполнение операторов в области, в которой возникла ошибка, поэтому первый пункт будет невозможен. Консоль позволяет вам это сделать.

В обычных условиях это было бы невозможно в дальнейшем, потому что код потерпел бы неудачу на этапе компиляции перед первым 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 берет ваш исходный код, разбивает его на строки (он же лексизирует его), берет эти строки и преобразует их в байт-код, понятный компилятору, а затем выполняет его.

Еще один урок глубокого погружения здесь.

Другие вопросы по тегам