2011-09-07 54 views
5

有問題的代碼很簡單:這種行爲的解釋是什麼? (當功能創建的?)

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

爲什麼foo()執行,它被定義(追溯編輯:在Chrome和Safari)之前?

我修修補補此一點,測試下面的代碼在Chrome,Safari和Firefox:

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

顯示在Chrome和Safari的警報,而Firefox保持沉默。

對這種令人驚訝的不一致的行爲有任何解釋嗎?

+0

什麼是控制檯輸出? – wosis

回答

3

當別人解釋功能的「吊裝」的行爲(我個人覺得叫它方面準備預處理吊裝更清晰)的Firefox的不同行爲的原因仍然沒有答案。

首先,您應該知道函數聲明和函數聲明之間的區別。

函數聲明,如在你的例子可能發生只在兩個地方,在全局代碼(以外的任何功能),並直接在另一個函數的函數體,例如:

function foo() {} 

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

所有上面的函數是有效的函數聲明。

ECMAScript規範不允許塊內定義在其他地方,例如函數聲明:

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

上述功能應該給你一個SyntaxError例外,但大多數的實現是仁慈的,他們即使實際功能無法到達(例如if (false) { function bar() {} }),仍會預處理(提升)該功能。

在Firefox中,函數語句是允許的,也就是說,當控制達到特定的語句,比如函數定義實際情況:

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

執行上面的語句後foo();,在Firefox中會產生true,因爲if語句的第一個分支實際執行。

在其他瀏覽器,foo();產生false,因爲所有的功能進行預處理進入執行上下文的時候,最後一個將優先考慮,即使if語句的false分支從未到達。

Firebug控制檯,執行其代碼封裝的一個try-catch塊內,這就是爲什麼功能不可用之前其聲明。

如果試圖在控制檯上:

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

你會看到f還沒有準備,但如果你換一個函數內部的代碼,您會看到預期的行爲:

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

同樣,這是因爲現在f被定義爲函數聲明,因爲它存在於匿名函數的主體中,而不是語句塊的一部分。

+0

感謝您付出努力打破這一點,感謝它。 – maligree

8

Javascript delarations總是會移動到頂部。這就是所謂的吊裝

例應在所有的瀏覽器: http://jsbin.com/abelus/edit

+2

首先,謝謝。其次,不,在所有瀏覽器中都不一樣 - 至少在撰寫本文時。我測試了您在Firefox 6.0.2上鍊接的示例代碼,並且沒有顯示「hello」。 – maligree

+0

@maligree,真的讓我感到驚訝。這個例子適用於Firefox 6:http://jsbin.com/abelus/2/edit。這似乎是jsbin的問題。 jsFiddle的工作原理:http://jsfiddle.net/vVhAc/ – binarious

3

你注意到的行爲叫做function hoisting

簡而言之,將使用語法function foo() { ... }定義的函數「懸掛」到定義範圍的頂部,從而允許在定義之前調用它們。

這就是說,這是JavaScript的一個不起眼的部分。如果瀏覽器的實現方式有所不同(特別是如果您使用的是舊版本的Firefox),這並不會讓我感到驚訝。

+0

+1起吊,例如-1;因爲在運行時檢測到'bar()'和'foo()'的存在(例如,當調用函數bar和foo時),遞歸的工作原理。 – Matt

+0

@Matt,好吧,我會被詛咒的。你是對的。我想我會刪除這個例子:) – riwalk

相關問題