Найти в Дзене
Сергей Б.

JavaScript/Всплытие

Всплытие или Hoisting - это способность интерпретатора знать о функциях или переменных еще до того, как они будут объявлены.

Посмотрим пример:

function sum( ) {
return a + b;
}
var a = 10;
var b = 10;
sum( ); // вернет 20

Объявляется функция, которая использует переменные a и b еще до того, как они были объявлены.

Чтобы понять почему такой код работает, можно представить себе, что перед выполнением кода, интерпретатор сканирует код на предмет переменных и перемещает их объявление в начало их областей видимости.

В результате, интерпретатор “видит” вышеуказанный так:

var a, b;
function sum( ) {
return a + b;
}
a = 10;
b = 10;
sum( ); // вернет 20

Теперь в коде нет ничего необычного и всё кажется более логичным: сначала объявляются переменные, затем им присваиваются значения и только после этого происходит вызов функции.

Обратите внимание, что “всплывают” только объявления переменных, но не присваивание им значений!

Посмотрите пример:

function sum( ) {
return a + b;
}
sum( ); // вернет NaN
var a = 10;
var b = 10;

Здесь, sum была вызвана до того, как переменным a и b были присвоены значения. А пока переменной не присвоено значение, ее значение равно undefined.

А undefined + undefined = NaN.

Вот так интерпретатор “увидит” данный код:

var a, b;
function sum( ) {
return a + b;
}
sum( ); // вернет NaN
a = 10;
b = 10;

На самом деле, всплытие - это побочный эффект от замыканий. Вспомним, что замыкание - это способность функции запоминать область видимости, в которой эта функция была объявлена.

Суть в том, что для замыкания не важно - выше или ниже по коду была объявлена переменная.

Это то, что касается всплытия переменных.

Теперь поговорим о том, что касается всплытия функций.

Посмотрим пример:

var a = 10;
var b = 10;
sum( ); // вернет 20
function sum( ) {
return a + b;
}

Обратите внимание, что функция объявлена после того, как был произведен ее вызов, но не смотря на это - код работает корректно.

Вспомним, что, перед выполнение кода, интерпретатор перемещает переменные в начало их областей видимости. Это же качается и функций.

Вот так интерпретатор будет “видеть” приведенный выше пример:

function sum( ) {
return a + b;
}
var a = 10;
var b = 10;
sum( ); // вернет 20

И опять же - теперь всё кажется более логичным.

Всплытие и function expression

Теперь, как и обещал, расскажу об основном отличии между function expression и function declaration.

Вспомним, что function declaration - это функция, объявленная в контексте другого выражения.

Давайте вернемся к примеру про всплытие функций:

var a = 10;
var b = 10;
sum( ); // вернет 20
function sum( ) {
return a + b;
}

А теперь изменим код так, чтобы sum была объявлена как function expression:

var a = 10;
var b = 10;
sum( ); // ошибка!
var sum = function( ) {
return a + b;
} ;

Такой код работать не будет, т.к. теперь sum является обычной переменной.

Вспомните, что при всплытии переменных, всплывает только их объявление, но не присвоение значений!

И вот как интерпретатор “увидит” этот код:

var a = 10;
var b = 10;
var sum;
sum( ); // ошибка!
sum = function( ) {
return a + b;
} ;

То есть, на момент вызова sum, внутри соответствующей переменной еще нет кода функции.