tl; dr Nếu bạn không gọi bất cứ điều gì cho đến khi mọi thứ tải, bạn sẽ ổn.
Chỉnh sửa: Để có một cái nhìn tổng quan cũng bao gồm một số khai báo ES6 ( let
, const
): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
Hành vi kỳ lạ này phụ thuộc vào
- Cách bạn xác định các chức năng và
- Khi bạn gọi cho họ.
Đây là một số ví dụ.
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();
Điều này là do một thứ gọi là cẩu !
Có hai cách để định nghĩa hàm: Khai báo hàm và biểu thức hàm . Sự khác biệt là khó chịu và phút, vì vậy chúng ta hãy nói điều này hơi sai: Nếu bạn đang viết nó giống như function name() {}
, đó là một khai báo và khi bạn viết nó như var name = function() {}
(hoặc một hàm ẩn danh được gán cho một kết quả trả về, những thứ tương tự), nó một biểu thức hàm .
Trước tiên, hãy xem cách các biến được xử lý:
var foo = 42;
//the interpreter turns it into this:
var foo;
foo = 42;
Bây giờ, cách khai báo hàm được xử lý:
var foo = 42;
function bar() {}
//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;
Các var
báo cáo "ném" các sáng tạo của foo
để phía trên đỉnh, nhưng không gán giá trị cho nó được nêu ra. Khai báo hàm đứng ở dòng tiếp theo và cuối cùng một giá trị được gán cho foo
.
Và điều này thì sao?
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
Chỉ khai báo của foo
được chuyển lên trên cùng. Việc chỉ định chỉ bar
được thực hiện sau khi lệnh gọi đến được thực hiện, nơi mà nó đã ở trước khi tất cả quá trình cẩu xảy ra.
Và cuối cùng, để ngắn gọn:
bar();
function bar() {}
//turns to
function bar() {}
bar();
Bây giờ, những gì về biểu thức hàm ?
var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Cũng giống như các biến thông thường, đầu tiên foo
được khai báo ở điểm cao nhất của phạm vi, sau đó nó được gán một giá trị.
Hãy xem tại sao ví dụ thứ hai lại gặp lỗi.
bar();
function bar() {
foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
foo();
}
bar();
foo = function() {}
Như chúng ta đã thấy trước đây, chỉ có quá trình tạo của foo
được lưu trữ, việc chuyển nhượng đến nơi mà nó xuất hiện trong mã "gốc" (không được nâng cấp). Khi nào bar
được gọi, trước đó nó foo
được gán một giá trị, vì vậy foo === undefined
. Bây giờ trong phần thân hàm của bar
, nó như thể bạn đang làm undefined()
, điều này tạo ra một lỗi.