Что такое Hoisting в JavaScript?
Введение
Hoisting (Хо́йстин(г)) - не самая известная особенность JavaScript, однако, знакомство с ней важно как для понимания кода, особенно старого, так и для осознания некоторых особенностей языка, о которых мы поговорим позже
Hoisting позволяет обращаться к функциям и переменным до их объявления в коде. Во время выполнения интерпретатор JavaScript "поднимает" их наверх
Переменные
Вот типичный пример демонстрации того, как Hoisting работает с переменными:
console.log(a); var a = 5; console.log(a);
Возникнет ли ошибка? Нет! Потому что код во время выполнения можно представить следующим образом:
var a; // Hoisting поднимает объявление переменной console.log(a); // undefined, так как здесь значения еще нет a = 5; // Теперь переменной присваивается значение console.log(a); // В консоль попадает корректное значение переменной - 5
Однако, говоря о переменных, это сработает только для устаревшего var
. Если мы попытаемся повторить этот трюк для let
или const
, мы получим ошибку:
console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization let b = 10; console.log(b);
Функции
Для функций Hoisting работает несколько иначе - в отличии от переменных, функции поднимаются вместе со своим телом:
sendGreeting(); // ✅ "Привет!" function sendGreeting() { console.log('Привет!'); }
Привычная история для JavaScript'а - не обошлось без нюансов. Hoisting работает только для Function Declaration
, то есть для функций, объявленных через ключевое слово function
как в примере выше. Если мы попытаемся воспользоваться таким трюком для Function Expression
, получим ошибку:
sendGreeting(); // ❌ TypeError: sayHi is not a function sendFarewell(); // ❌ ReferenceError: Cannot access 'sendFarewell' before initialization /** * Даже не смотря на ключевое слово function в объявлении, это все еще * Function Expression, так как функция записывается в переменную * и здесь Hoisting работает как в примере с переменными */ var sendGreeting = function () { console.log('Привет!'); }; // Предсказуемо, современный вариант тоже не сработает const sendFarewell = () => console.log('Пока!');
Таким образом, если мы, например, в одном файле собираем библиотеку функций и какие-то из них используют соседние, объявление через function
позволит избежать потенциальных ошибок и ускорит отладку
Заключение
Однозначно можно заключить одно. Hoisting - сбивающее с толку неочевидное поведение. Во многих других языках вы сразу получите ошибку, если попытаетесь использовать функцию или прочитать переменную до объявления. Это предсказуемо и гораздо логичнее, чем в JavaScript, предоставляющем разработчикам намного больше свобод
Моя рекомендация - не полагаться на существование такой особенности языка, а следить за порядком объявления и использования функций самостоятельно. Такая практика позволит лучше продумать структуру кода и сильно упростит его чтение, следовательно, понимание