Поднятие (hoisting) в JS
В этой статье вы познакомитесь с понятием hoisting в JavaScript.
Поднятие (hoisting) — это поведение, при котором функцию или переменную можно использовать до объявления.
Поднятие предполагает, что объявления переменных и функций физически перемещаются в начало кода — «поднимается».
Например:
// используем переменную test
console.log(test); // вывод: undefined
// объявляем переменную test
var test;
Эта программа выведет в консоль значение undefined
.
Аналогично ведет себя такая программа:
// объявляем переменную
var test;
// используем переменную
console.log(test); // вывод: undefined
Поскольку переменная test
объявлена, но не инициализирована (ей ни присвоено никакое значение), JavaScript определяет ее как undefined
.
Поднятие переменных
Ключевое слово var
поддерживает hoisting, а вот let
и const
— нет.
Пример:
a = 5;
console.log(a);
var a; // значение a — 5
В приведенном выше примере переменная a
используется до объявления. Программа работает и выводит на экран значение 5.
Аналогично будет работать следующая программа:
var a;
a = 5;
console.log(a); // значение a — 5
Не поддерживает инициализацию
JavaScript не поддерживает поднятие с инициализацией. То есть так hoisting работать не будет:
console.log(a); // вывод: undefined
var a = 5;
Аналогично будет работать следующая программа:
var a;
console.log(a); // вывод: undefined
a = 5;
На этапе компиляции в память переносится только объявление. Поэтому значение переменной a
— undefined
, поскольку мы выводи на экран a
без инициализации.
Внутри функции — поднятие только до начала функции
Когда переменная используется внутри функции, ее можно поднять только в начало функции.
// program to display value
var a = 4;
function greet() {
b = 'привет';
console.log(b);
var b;
}
greet(); // вывод: привет
console.log(b);
Вывод:
привет Uncaught ReferenceError: b is not defined
В этом примере переменная b
поднимается в начало функции greet()
и становится локальной переменной. Это значит, что b
доступна только внутри функции. Отсюда возникает ошибка, когда мы пытаемся получить доступ к b
вне функции greet()
.
Примечание. При объявлении переменной с поднятием переменная доступна только в той области видимости, в которой она объявлена.
С let нельзя
Если переменная объявлена с помощью ключевого слова let
, применить к ней hoisting нельзя.
a = 5;
console.log(a);
let a; // ошибка
Вывод:
Uncaught ReferenceError: Cannot access 'a' before initialization
При использовании let
сначала объявление, потом использование.
Поднятие функций
Функцию можно также вызвать до ее объявления.
greet();
function greet() {
console.log('Приветики.');
}
Вывод:
Приветики.
В это примере функция greet()
вызывается до ее объявления, и программа все равно показывает вывод. Это происходит из-за hoisting.
С функциональными выражениями нельзя
Если определить функцию в виде выражения при поднятии, возникнет ошибка. Причина: поднимаются только объявления.
greet();
let greet = function() {
console.log('Приветики.');
}
Вывод:
Uncaught ReferenceError: greet is not defined
Использование var
здесь не поможет. Все равно будет ошибка:
Uncaught TypeError: greet is not a function
Примечание. Поднятие не используется в других языках программирования: Python, C, C++, Java.
Важно учитывать, что hoisting может привести к нежелательным последствиям в вашей программе. Поэтому лучше сначала объявлять переменные и функции перед использованием — избегать поднятий.
А в случае с переменными лучше использовать let, а не var.