2011-09-07 27 views
5

Mã trong câu hỏi rất đơn giản:Giải thích về hành vi này là gì? (Khi được chức năng tạo?)

console.log("So it begins."); 
foo(); 
function foo() { console.log("In foo()."); } 
console.log("So it ends."); 

Tại sao foo() thực hiện, trước khi nó được định nghĩa (hồi chỉnh sửa: trong Chrome và Safari)?

tôi tinkered với điều này một chút, thử nghiệm đoạn mã sau trong Chrome, Safari và Firefox:

javascript:foo();function foo() { alert("Oh."); } 

Một cảnh báo sẽ được hiển thị trong Chrome và Safari, trong khi Firefox vẫn im lặng.

Có giải thích nào về hành vi bất thường, không nhất quán này không?

+0

Đầu ra bàn điều khiển là gì? – wosis

Trả lời

3

khi những người khác đã giải thích "cẩu" hành vi của các chức năng (cá nhân tôi thấy gọi đó là chuẩn bị bối cảnh hoặc tiền xử lý hơn rõ ràng hơn cẩu) lý do của hành vi khác nhau của Firefox vẫn chưa được trả lời.

Để bắt đầu, bạn nên biết sự khác biệt giữa Tuyên bố chức năng và Tuyên bố chức năng .

Một Tuyên bố Chức năng, như trong ví dụ của bạn có thể chỉ xảy ra ở hai nơi, trong mã toàn cầu (bên ngoài của bất kỳ chức năng) và trực tiếp trong cơ thể Chức năng của chức năng khác, ví dụ:

function foo() {} 

function bar() { 
    function baz() {} 
} 

Tất cả các các hàm trên là các Khai báo hàm hợp lệ.

Các ECMAScript Đặc điểm kỹ thuật không cho phép để xác định khai báo Chức năng ở những nơi khác ví dụ trong Blocks:

if (true) { 
    function foo() {} 
} 

Chức năng trên nên cung cấp cho bạn một ngoại lệ SyntaxError, nhưng hầu hết các trường là nhân từ, và họ vẫn sẽ xử lý trước (hoist) chức năng, ngay cả khi không thể truy cập chức năng thực tế (ví dụ: if (false) { function bar() {} }).

Trong Firefox, cáo Chức năng được phép, có nghĩa là định nghĩa hàm thực sự xảy ra khi sự kiểm soát đạt rằng tuyên bố cụ thể, ví dụ:

if (true) { 
    function foo() { return true; } 
} else { 
    function foo() { return false; } 
} 

Thi foo(); sau khi các báo cáo trên, trong Firefox sẽ sản xuất true, bởi vì nhánh đầu tiên của câu lệnh if thực sự được thực thi.

Trong các trình duyệt khác, foo(); sản xuất false bởi vì tất cả các chức năng là tiền xử lý khi bước vào bối cảnh thực hiện, và người cuối cùng sẽ được ưu tiên, ngay cả khi false chi nhánh của báo cáo kết quả ifbao giờ đạt được.

Bảng điều khiển Firebug, thực thi mã của nó gói trong khối try-catch, đó là lý do tại sao hàm này không có sẵn trước khi khai báo.

Nếu bạn cố gắng trên console:

console.log(typeof f); // "undefined" 
function f() {} 

Bạn sẽ thấy rằng f không được chuẩn bị, nhưng nếu bạn quấn mã của bạn bên trong một hàm, bạn sẽ thấy những hành vi mong đợi:

(function() { 
    console.log(typeof f); // "function" 
    function f() {} 
})(); 

Một lần nữa, đó là vì bây giờ f được định nghĩa là Tuyên bố hàm, vì nó tồn tại trong phần nội dung của hàm ẩn danh và không phải là một phần của khối lệnh.

+0

Cảm ơn những nỗ lực đưa vào phá vỡ này xuống, đánh giá cao nó. – maligree

8

Các yêu cầu Javascript luôn được chuyển lên trên cùng. Nó được gọi là cẩu:

Ví dụ mà nên làm việc trong tất cả các trình duyệt: http://jsbin.com/abelus/edit

+2

Thứ nhất, cảm ơn. Thứ hai, không, nó không hoạt động giống nhau trong tất cả các trình duyệt - ít nhất là tại thời điểm viết. Tôi đã kiểm tra mã ví dụ bạn đã liên kết với trên Firefox 6.0.2 và không có "hello" được hiển thị. – maligree

+0

@maligree, điều đó thực sự làm tôi ngạc nhiên. Ví dụ này hoạt động trong Firefox 6: http://jsbin.com/abelus/2/edit. Nó có vẻ là một vấn đề với jsbin. jsFiddle hoạt động: http://jsfiddle.net/vVhAc/ – binarious

3

hành vi bạn nhận thấy được gọi là function hoisting.

Tóm lại, các hàm được xác định bằng cú pháp function foo() { ... } được "treo" lên đầu phạm vi mà chúng được xác định, do đó cho phép chúng được gọi trước khi được xác định.

Với điều đó được nói, đây là phần tối nghĩa của JavaScript. Nó sẽ không làm tôi ngạc nhiên nếu có sự khác biệt trong cách trình duyệt thực hiện nó (đặc biệt là nếu bạn đang sử dụng một phiên bản cũ của firefox).

+0

+1 cho cẩu, -1 cho ví dụ; phép đệ quy hoạt động vì sự tồn tại của 'bar()' và 'foo()' được phát hiện trong thời gian chạy (ví dụ: khi gọi các hàm 'bar' và' foo'.) – Matt

+0

@Matt, tôi sẽ bị chết tiệt. Bạn đúng. Tôi đoán tôi sẽ loại bỏ ví dụ :) – riwalk

Các vấn đề liên quan