Объяснение Hoisting в JavaScript с помощью визуализации
Это перевод статьи Лидии Холли, где она разбирает такое понятие как Hoisting.
Hoisting — это один из тех терминов, о котором слышал каждый разработчик JS, потому что вы наверняка гуглили ошибку и попали на StackOverflow, где вам объяснили, что эта ошибка была связана с "hoisting" 🙃 Итак, что такое hoisting?
Если вы начинающий в разработке на JavaScript, возможно, вы столкнулись с «странным» поведением, когда некоторые переменные undefined
, возникают ошибки ReferenceErrors
и т.д. Hoisting часто объясняется помещением переменных и функций в начало файла, но нет, это не то, что происходит на самом деле, давайте разбираться почему так.
Когда JS-движок получает наш скрипт, первое, что он делает, - это сетапит память для данных в нашем коде. На этом этапе код не выполняется, просто все готовится к выполнению. Способ хранения объявлений функций и переменных отличается. Функции хранятся со ссылкой на всю функцию:
С переменными все немного иначе. ES6 представил два новых ключевых слова для объявления переменных: let
и const
. Переменные, объявленные с помощью ключевого слова let
или const
, сохраняются неинициализированными:
Переменные, объявленные с помощью ключевого слова var
, сохраняются со значением по умолчанию undefined
.
Теперь, когда этап создания завершен, мы можем фактически выполнить код. Давайте посмотрим, что произойдет, если у нас есть 3 оператора console.log вверху файла до того, как мы объявим функцию или любую из переменных.
Поскольку функции хранятся со ссылкой на весь код функции, мы можем вызывать их даже перед строкой, в которой мы их создали.
Когда мы ссылаемся на переменную, объявленную с ключевым словом var
перед их объявлением, она просто возвращает значение по умолчанию, с которым она была сохранена: undefined
. Однако иногда это могло привести к «неожиданному» поведению. В большинстве случаев это означает, что вы ссылаетесь на него непреднамеренно (вы, вероятно, не хотите, чтобы он действительно имел значение undefined
) 😬
Чтобы предотвратить возможность случайной ссылки на неопределенную переменную, как мы могли бы с ключевым словом var, при каждой попытке доступа к неинициализированным переменным выдается ошибка ReferenceError. "Зона" перед их фактическим объявлением называется временной мертвой зоной: вы не можете ссылаться на переменные (включая классы ES6!) До их инициализации.
Когда движок передает строку, в которой мы фактически объявили переменные, значения в памяти перезаписываются значениями, с которыми мы их фактически объявили.
Резюме: функции и переменные хранятся в памяти execution context'a до того, как мы выполним наш код. Это называется Hoisting.