Всплытие или 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, внутри соответствующей переменной еще нет кода функции.