tl; dr. Якщо ви нічого не телефонуєте, поки все не завантажиться, вам слід добре.
Редагування: огляд, який також охоплює деякі декларації ES6 ( let
, const
): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
Від цієї дивної поведінки залежить
- Як ви визначаєте функції та
- Коли ви їх телефонуєте.
Ось кілька прикладів.
bar(); //This won't throw an error
function bar() {}
foo(); //This will throw an error
var foo = function() {}
bar();
function bar() {
foo(); //This will throw an error
}
var foo = function() {}
bar();
function bar() {
foo(); //This _won't_ throw an error
}
function foo() {}
function bar() {
foo(); //no error
}
var foo = function() {}
bar();
Це через щось, що називається підйомом !
Існує два способи визначення функцій: оголошення функції та вираження функції . Різниця дратівлива і хвилинна, тому скажемо лише про цю трохи неправильну річ: якщо ви пишете це так function name() {}
, це декларація , а коли ви пишете так var name = function() {}
(або анонімна функція, призначена для повернення, подібні речі), це вираження функції .
Спочатку розглянемо, як обробляються змінні:
var foo = 42;
//the interpreter turns it into this:
var foo;
foo = 42;
Тепер, як обробляються декларації функцій :
var foo = 42;
function bar() {}
//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;
У var
відомості «кидає» на створення в foo
до самого верху, але не привласнює значення для неї ще. Наступний рядок стає декларацією функції, і нарешті присвоюється значення foo
.
А що з цим?
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
На початок переміщується лише декларація про foo
. Призначення відбувається лише після здійснення дзвінка на місце bar
, де це було раніше, ніж відбулося все підйомне обладнання.
І нарешті, для стислість:
bar();
function bar() {}
//turns to
function bar() {}
bar();
А тепер, що з виразами функцій ?
var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Так само , як і звичайні змінні, перший foo
буде оголошений в найвищій точці сфери, то йому присвоюється значення.
Подивимось, чому другий приклад видає помилку.
bar();
function bar() {
foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
foo();
}
bar();
foo = function() {}
Як ми бачили раніше, тільки створення foo
піднімається, це завдання відбувається там, де воно з'явилося в "оригінальному" (непіднятому) коді. Коли bar
викликається, перед цим foo
присвоюється значення, так foo === undefined
. Зараз у тілі функції bar
, це як ніби ви робите undefined()
, що видає помилку.