javascript
March 21

Что такое 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, предоставляющем разработчикам намного больше свобод

Моя рекомендация - не полагаться на существование такой особенности языка, а следить за порядком объявления и использования функций самостоятельно. Такая практика позволит лучше продумать структуру кода и сильно упростит его чтение, следовательно, понимание