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()
, что выдает ошибку.