Когда вы учились программировать на JavaScript, преподаватели, наставники или случайные люди на StackOverflow говорили вам, что вы хотите избежать проблем с подъемом в коде, используя const
или let
.
Но вы спрашиваете себя, что это за чертовщина — hoisting, и почему я должен избегать его? Ну, это как раз то, что нужно!
Hoisting — это когда движок JavaScript перемещает объявления переменных и функций в верхнюю часть их соответствующей области видимости перед выполнением кода.
Пример объявления переменной Hoisting:
x = 6
var x;
console.log(x)
// x would be equal to 6 with no errors thrown
Естественно, вы подумаете, что этот код не будет работать, потому что вы не можете присвоить переменную и затем разместить объявление под ней, верно?
Но вы можете сделать именно это с помощью var
, потому что он инициализирует переменные перед объявлением, позволяя JavaScript поднять ее в начало функции и не выдать никаких ошибок.
Пример поднятия в объявлении функции:
dogBreed('Miniature Schnauzer')
function dogBreed(name) {
console.log('My favorite dog breed is the ' + name + '!')
}
// My favorite dog breed is the Miniature Schnauzer!
Хотя этот код работает нормально, для удобочитаемости лучше избегать вызова функций до их объявления.
Смешивание этих двух понятий может привести к очень запутанному коду. Возьмем, к примеру, этот фрагмент кода:
var dogBreed = "Pug";
var favDogBreed = function () {
console.log("My favorite dog breed: " + dogBreed);
var dogBreed = "Shih Tzu";
console.log("Bob's favorite dog breed: " + dogBreed);
};
favDogBreed();
// Original favorite dog: undefined
// New favorite dog: Shih Tzu
Как ни странно, JavaScript инициализировал первую переменную dogBreed значением undefined
, потому что она была поднята, а затем начал выполнять функцию, поэтому мы и получили такой результат.
Переменные, которые инициализируются в JavaScript, однако, не поднимаются. Интересно, что в приведенном ниже фрагменте кода выводится NaN
:
console.log(x + y)
var x = 4
var y = 2
// Output is NaN
Это происходит потому, что JavaScript поднимает x
и y
, но не их соответствующие инициализации = 4
и = 2
, что приводит к NaN
, потому что x
и y
не являются числами!
К счастью, в 2015 году появилась новая версия JavaScript ES6, в которой были введены let
и const
, которые фактически устарели var
.
Рассмотрим еще раз favDogBreed
, но объявим все с помощью let
вместо var
:
let dogBreed = "Pug";
let favDogBreed = function () {
console.log("My favorite dog breed: " + dogBreed);
let dogBreed = "Shih Tzu";
console.log("Bob's favorite dog breed: " + dogBreed);
};
favDogBreed();
// This will throw a ReferenceError and not let this code run
Теперь все в порядке в мире, и инженеру придется пойти и исправить свой запутанный код.
Однако то, что ошибки теперь не возникают, не означает, что hoisting вычеркнут из Javascript. Он по-прежнему возникает с переменными, объявленными с помощью let
и const
, но они никогда не инициализируются. Возьмем, к примеру, этот фрагмент кода:
dogName = "Sparky";
const dogName
console.log(dogName)
// This code doesn't run
dogName = "Sparky";
let dogName
console.log(dogName)
// This results in a ReferenceError
Что это значит? Для начала, подъем все еще происходит с этими переменными, объявленными с помощью let
и const
, но есть некоторые различия.
const
отказывается выполняться из-за синтаксической ошибки. То же самое происходит с let
, но JavaScript видит переменную и знает о ней, но JavaScript не может использовать переменную, пока она не будет правильно объявлена.
При объявлении с помощью let
, наша переменная dogName
находится в явлении, называемом временной мертвой зоной, которое да, было бы самым тошнотворным названием для группы, но это то, в чем находится переменная, объявленная с помощью let
или const
, пока JavaScript не достигнет и не выполнит строку, в которой объявлена переменная.
Временная мертвая зона не применяется к var
, потому что JavaScript инициализирует переменную в неопределенное значение, когда к ней обращаются до объявления.
Лучшая практика для предотвращения проблем с подъемом заключается в следующем:
-
Объявлять переменные и функции
let
иconst
везде, где это возможно. -
Всегда объявляйте переменные в начале каждой области видимости, потому что именно так JavaScript и разработчики читают код.
-
Никогда не используйте
var
.
Поздравляем! Теперь у вас есть лучшее представление о hoisting и о том, как он работает в JavaScript ES6. Эта (часто упускаемая из виду) концепция сбивает с толку разработчиков, как новичков, так и ветеранов, и у вас есть преимущество в понимании и предотвращении ошибок, связанных с hoisting в JavaScript!
Вот некоторые дополнительные ресурсы по этой теме:
W3Schools
MDN
JavaScript Docs