Время жизни переменной JavaScript: почему let не поднимается

внешний интерфейс алгоритм GitHub JavaScript
Время жизни переменной JavaScript: почему let не поднимается

Оригинальная ссылка:Рисовое путешествие avlutin.com/variables-come…

Поднятие на самом деле является процессом перемещения определений переменных и функций в верхнюю часть области видимости, что обычно происходит в объявлениях переменных.varили объявление функцииfunction fun() {...}.

когдаlet(включая иletимеют такое же заявленное поведениеconstа такжеclass) был представлен ES2015, и многие разработчики, в том числе и я, использовали подъем для описания доступа к переменным. Но, проведя еще несколько поисков по этому вопросу, к моему удивлению, повышение не является описаниемletПравильный термин для инициализации и доступности переменных.

ES2015 даетletПредусмотрены различные и улучшенные механизмы. Это требует более строгой практики объявления переменных (нельзя использовать, пока не определено), поэтому будет более качественный код.

Давайте рассмотрим процесс более подробно.

1. Склонность к ошибкамvarпродвигать

Иногда я вижу странную практику, переменнуюvar varnameи функцияfunction funcName() {...}Объявите в любом месте области видимости:

// var hoisting
num;     // => undefined  
var num;  
num = 10;  
num;     // => 10  
// function hoisting
getPi;   // => function getPi() {...}  
getPi(); // => 3.14  
function getPi() {  
  return 3.14;
}

numпеременная вvar numЗаявление было доступно ранее, поэтому он считаетсяundefined.

функцияfunction getPi() {...}определяется в конце. Поскольку он поднимается наверх области видимости, функция может быть определенаgetPi()звонили раньше.

Это типичное усиление.

Оказывается, объявление переменной или функции после использования может сбивать с толку. Предположим, вы просматриваете большой файл и вдруг видите необъявленную переменную... как она сюда попала и где она определена?

Конечно, опытный разработчик JavaScript не стал бы писать код таким образом, но очень вероятно, что вы столкнетесь с таким кодом в тысячах репозиториев JavaScript GitHub.

Даже глядя на пример кода, приведенный выше, трудно понять поток объявлений в коде.

Естественно, сначала объявляется или описывается неизвестное слово, и только потом оно используется для написания словосочетания.letСледуя этому подходу, рекомендуется использовать переменные.

2. Исследуйте нижний слой: жизненный цикл переменных

Когда движок обращается к переменным, их жизненный цикл включает следующие этапы:

  1. Фаза объявления: зарегистрируйте переменную в области видимости
  2. Фаза инициализации: выделение памяти и создание привязок к переменным в области видимости. На этом этапе переменная автоматически инициализируетсяundefined
  3. Фаза присваивания: присвоение значения уже инициализированной переменной

Переменная, прошедшая стадию объявления, но не дошедшая до стадии инициализации, находится в неопределенном состоянии.

Обратите внимание, что фаза объявления и объявление переменной в целом — это разные термины, зависящие от срока жизни переменной. Вкратце, механизм обрабатывает объявления переменных в три этапа: этап объявления, этап инициализации и этап назначения.

3.varпеременный жизненный цикл

Знакомые с фазами жизненного цикла, мы используем их для описания того, как работает движок.varПеременная.

Предположим сценарий, когда JavaScript сталкивается с областью действия сvarФункция объявленной переменной. Эта переменная проходит фазу объявления и фазу инициализации (первый шаг) перед выполнением любого оператора.

var variableПоложение объявления в области действия функции не влияет на этапы объявления и инициализации.

После объявления и инициализации, но перед фазой присваивания значение переменнойundefinedи могут быть доступны для использования.

На этапе назначения,variable = 'value', переменная получает свое начальное значение (шаг 2).

Строго говоря, концепция подъема заключается в объявлении и инициализации переменных в верхней части области видимости функции. Между фазами объявления и инициализации нет разрыва.

Давайте изучим пример. Следующий код создаетvarПеременная функция:

function multiplyByTen(number) {  
  console.log(ten); // => undefined
  var ten;
  ten = 10;
  console.log(ten); // => 10
  return number * ten;
}
multiplyByTen(4); // => 40

Когда JavaScript начинает выполнятьсяmultipleByTen(4), оно вошлоmultipleByTenОбласть действия функции, перед первым оператором, переменнаяtenФаза объявления и инициализации завершена. так позвониconsole.log(ten)распечатаетundefined.

утверждениеten = 10Присваивается начальное значение. После выделения,console.log(ten)10 правильно вывод.

4. Жизненный цикл декларации функции

Предположим, оператор объявления функцииfunction funName() {...}, что проще.

Фазы объявления, инициализации и присваивания выполняются немедленно (только один шаг) в начале области действия функции.funcName()Может вызываться в любом месте области видимости, независимо от того, где объявлен оператор (даже в конце).

В следующем примере кода демонстрируется подъем функции:

function sumArray(array) {  
  return array.reduce(sum);
  function sum(a, b) {
    return a + b;
  }
}
sumArray([5, 10, 8]); // => 23  

Когда JavaScript вызываетsumArray([5, 10, 8]), оно вошлоsumArrayобъем функции. Внутри области, прежде чем все операторы будут выполнены,sumПрошел три этапа: объявление, инициализация, присваивание. Сюда,array.reduce(sum)даже в объявлении заявлениеfunction sum(a, b) {...}использовался раньшеsum.

5.letпеременный жизненный цикл

letКак обрабатываются переменные иvarразные. Основное отличие состоит в том, что этапы объявления и инициализации разделены.

Теперь предположим, что интерпретатор входит в область действия блока, содержащуюlet variableутверждение. Переменная сразу проходит фазу объявления, регистрируя свое имя в области видимости (шаг 1).

Затем интерпретатор анализирует оператор построчно.

Если вы попытаетесь получить доступ к переменной на этом этапеvariableJavaScript броситReferenceError: variable is not defined. Потому что состояние переменной не определено,variableво временной мертвой зоне.

когда придет переводчикlet variableоператор, фаза инициализации проходит (шаг 2). Теперь состояние переменной определено, и доступ к ней дастundefined.

Переменная выходит из временной зоны нечувствительности.

Позже, когда оператор присваиванияvariable = 'value'появляется, пройдя фазу назначения (шаг 3).

Если JavaScript встречаетlet variable = 'value', то инициализация и присваивание будут происходить в этом единственном операторе.

Давайте посмотрим на пример. используется в области блокаletобъявить переменнуюvariable:

let condition = true;  
  // console.log(number); // => Throws ReferenceError
  let number;
  console.log(number); // => undefined
  number = 5;
  console.log(number); // => 5
}

когда входит javascriptif (condition) {...}При блочной области видимостиnumberСразу прошел этап декларирования. потому чтоnumberнаходится в неопределенном состоянии, во временной мертвой зоне, попытка доступа к этой переменной выдаетReferenceError: number is not defined.

Позднее приговорlet numberИнициализация завершена. Теперь переменная доступна, но ее значение равноundefined.

оператор присваиванияnumber = 5Разумеется, этап задания завершен.

constа такжеclassтип иletимеют одинаковое время жизни, за исключением того, что присвоение может произойти только один раз.

5.1 Зачем подниматьletнедействителен при жизни

如上所述,提升就是变量在作用域顶部进行声明和初始化。 ноletЖизненный цикл объявит и инициализирует два этапа отделен. Разделение позволяет восхождение на срок неэффективной.

Промежуток между двумя этапами создает временную мертвую зону, где переменные недоступны.

в научно-фантастическом стилеletКрах термина вознесение создает временную мертвую зону в течение жизненного цикла.

6. Заключение

Не стесняйтесь использоватьvarОбъявление переменных подвержено ошибкам. На основе этого урока ES2015 создалlet. Он использует улучшенный алгоритм объявления переменных и область видимости на уровне блоков.

Благодаря разделению фаз объявления и определения, подъем дляletобъявленные переменные (включаяconstа такжеclass)неверный. До инициализации переменная находится во временной мертвой зоне и недоступна.

Чтобы поддерживать стабильные объявления переменных, даются следующие рекомендации:

  • Объявите, инициализируйте и затем используйте переменную. Процесс правильный и простой для понимания;
  • Максимально скройте переменные. Чем меньше переменных выставлено, тем более модульным является код.