tl; dr Jeśli nie dzwonisz, dopóki wszystko się nie załaduje, powinno być dobrze.
Edycja: przegląd obejmujący również niektóre deklaracje ES6 ( let
, const
): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
To dziwne zachowanie zależy od
- Jak definiujesz funkcje i
- Kiedy do nich dzwonisz.
Oto kilka przykładów.
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();
To z powodu czegoś, co nazywa się podnoszeniem !
Istnieją dwa sposoby definiowania funkcji: deklaracja funkcji i wyrażenie funkcji . Różnica jest irytująca i niewielka, więc powiedzmy trochę zła rzecz: jeśli piszesz to w ten sposób function name() {}
, jest to deklaracja , a kiedy piszesz to jako var name = function() {}
(lub anonimowa funkcja przypisana do zwrotu, takie rzeczy), to wyrażenie funkcyjne .
Najpierw przyjrzyjmy się, jak obsługiwane są zmienne:
var foo = 42;
//the interpreter turns it into this:
var foo;
foo = 42;
Teraz, jak obsługiwane są deklaracje funkcji :
var foo = 42;
function bar() {}
//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;
Te var
stwierdzenia „rzuca” na tworzenie się foo
na samym szczycie, ale jeszcze nie przypisać wartość do niego. Deklaracja funkcji jest następna w linii, a na końcu przypisywana jest wartość foo
.
A co z tym?
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
Tylko deklaracja od foo
przesuwa się do góry. Przypisanie następuje dopiero po wezwaniu bar
, gdzie było przed całym podniesieniem.
I wreszcie, dla zwięzłości:
bar();
function bar() {}
//turns to
function bar() {}
bar();
A co z wyrażeniami funkcyjnymi ?
var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Podobnie jak zwykłe zmienne, najpierw foo
zostanie ogłoszony w najwyższym punkcie zakresu, to jest przypisana wartość.
Zobaczmy, dlaczego drugi przykład generuje błąd.
bar();
function bar() {
foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
foo();
}
bar();
foo = function() {}
Jak widzieliśmy wcześniej, tylko tworzenie foo
jest podnoszone, przypisanie pojawia się tam, gdzie pojawiło się w „oryginalnym” (niewniesionym) kodzie. Kiedy bar
jest wywoływana, to jest wcześniej foo
przypisywana wartość, więc foo === undefined
. Teraz w treści funkcji bar
jest to tak, jakbyś robił undefined()
, co powoduje błąd.