2016-02-04 40 views
2

這裏是例子:爲什麼「TypeError:f不是函數」?

var f = function(x) { 
 
    alert(x) 
 
} 
 

 
(function() { 
 
    f(1) 
 
}())

爲什麼

TypeError: f is not a function"?

+0

類似問題:http://stackoverflow.com/questions/23587441/javascript-strange-loading-sequence/23587563#23587563 – dfsq

+0

謝謝你的編輯! –

回答

5

這是自動插入分號讓您失望的情況下,代碼被解釋爲IIFE:

var f = function(x) { 
    alert(x) 
}(function() { 
    f(1) 
}()) 

所以這就是爲什麼f確實沒有定義。

所以經驗法則:永遠不要用([開始行。然後你可以安全地省略分號。

+0

謝謝你的回答! –

+2

開始與parens一條線是非常常見的IIFEs。我認爲在* parens和大括號之後使用分號*可能會更好。 – ssube

+0

@ssube我知道,但這是忽略分號的唯一可能的問題。 IIFE可以使用額外的分號開始:';(function(){...}())'。 – dfsq

11

在你的例子中,f不是一個函數。如果你改變的例子,它是:

var f = function(x) { 
    alert(x) 
}; 

(function() { 
    f(1) 
}()); 

你相抵觸的automatic semicolon insertion運行(或其缺乏)。

由於ASI規則,如果一行不以分號結束,解析器可以組合行。在你的情況,缺乏var f = function語句後分號會導致解析器申報,並立即調用函數,f被初始化之前,並嘗試結果分配給f

var f = function(x) { 
    alert(x) 
}(function() { 
    f(1) 
}()) 

只需插入分號,則強制解析器打破這兩個語句,並且代碼的行爲與您所期望的相同。

解析器更喜歡將它們結合起來,因爲它看到一個函數,看起來像是參數(由於括號中的空格,空白被忽略)。它調用剛剛聲明的函數,然後調用f,但f尚未初始化,因此不是函數。

我在舊的web應用程序中遇到了一個特別有趣的案例(在webpack和browserify存在以合併文件之前):我們只是按順序一起捕獲我們的JS文件,大部分都在IIFE模塊中。一個腳本在其模塊後面沒有以分號結尾,因此下一個模塊在初始化第一個模塊時作爲參數傳遞。這是一個痛苦的發現,因爲它發生在應用程序的早期,是一個單一的失蹤半。

在這種情況下,我們能夠通過在我們串聯的文件之間添加註釋來修改問題而不更改任何外部代碼,但最好的做法是用分號和換行符結束您的代碼。它避免了像這樣的稀有空白錯誤。

+0

謝謝你的回答! –

相關問題