При изучении JavaScript первое, что мы слышим о переменных JS, это то, что var поднимается, тогда как let и const не поднимаются.

Но так ли это на самом деле? Технически НЕТ.

Миф # 1

Подъем: движок JS физически размещает переменные в верхней части кода во время выполнения.

Согласно MDN: концептуально, например, строгое определение подъема предполагает, что объявления переменных и функций физически перемещаются в верхнюю часть вашего кода, но на самом деле это не то, что происходит. Вместо этого объявления переменных и функций помещаются в память на этапе компиляции, но остаются там, где вы ввели их в код.

Миф 2.

Подняты var переменных. let и const нет.

Технически все переменные JS подняты. Где let и cost отличается от var в процессе подъема, находится в части инициализации.

Почему мы получаем ReferenceError при доступе к переменным 'let' перед их объявлением? 🤔

Жизненный цикл переменной

Предварительное информирование: движок JavaScript интерпретирует ваш код в два отдельных этапа. Фаза компиляции и фаза выполнения. да. Вы не ослышались. JS компилируется.

Двигаясь дальше, переменная JS технически имеет 3 фазы.

  1. Фаза объявления: переменная регистрируется в области действия.
  2. Этап инициализации: переменная инициализируется с помощью undefined.
  3. Этап присвоения: переменной присваивается значение.

Примечание. Не путайте этап объявления и объявление переменной: этап объявления выполняется компилятором JS, а объявление переменной - это явный код, написанный пользователем, т.е. var foo;

Жизненный цикл var

  1. Этап объявления: время компиляции.
  2. Этап инициализации: время компиляции.
  3. Этап назначения: время выполнения.

Для var фаза инициализации выполняется сразу после фазы объявления. И оба они выполняются во время компиляции.

Сравнивая этот пример с фазовой диаграммой,

  1. Фаза объявления + фаза инициализации: foo добавляется в область и автоматически присваивается undefined в качестве значения во время компиляции.
  2. Казнь начинается.
  3. JS проверяет foo в области и находит его значение как undefined.
  4. Фаза присвоения: foo присваивается значение 2.

Жизненный цикл аренды

  1. Этап объявления: время компиляции.
  2. Этап инициализации: время выполнения.
  3. Этап назначения: время выполнения.

Для let фаза объявления выполняется во время компиляции. Но в отличие от var, этап инициализации выполняется не сразу после этапа объявления, а во время выполнения.

В начале фазы выполнения переменные let объявляются, но не инициализируются. Эти переменные инициализируются только тогда, когда движок JS достигает ключевого слова let.

До тех пор считается, что переменная находится в временной мертвой зоне.

Получение или установка неинициализированных переменных, находящихся в TDZ, приведет к ReferenceError.

Сравнивая этот пример с фазовой диаграммой,

  1. Фаза объявления: foo добавляется в область видимости во время компиляции.
  2. Казнь начинается. Foo в настоящее время не инициализирован и не имеет никакого значения, даже undefined. Доступ к foo в этот момент дает ReferenceError.
  3. Этап инициализации: когда механизм JS обнаруживает ключевое слово let, foo назначается undefined.
  4. Фаза присвоения: foo присваивается значение 2.

Фактически, несколько других операторов также ведут себя аналогично let. Например: const, class

TL;DR

  1. Технически var, let и const подняты.
  2. var объявляется и инициализируется во время подъема.
  3. let и const объявляются только во время подъема, но не инициализируются. Доступ к неинициализированным переменным приводит к ReferenceError .
  4. По возможности предпочитайте 38_ 39, чтобы избежать путаницы, связанной с подъемом.
  5. По возможности предпочитайте const let, чтобы иметь строгий контроль над переменными, которые не должны изменяться.