立即調用的函數表達式(IIFE)
在JavaScript中,圓括號 () 是一種運算符,跟在函數名之後,表示調用該函數。比如, print() 就表示調用 print 函數。
有時,我們需要在定義行數之後,立即調用該函數。這時,你不能在函數的定義之後加上圓括號,這會產生語法錯誤。
function(){/* code */}; // SyntaxError: Unexpected token (
產生這個錯誤的原因是, function 這個關鍵字即可以當做語句,也可以當作表達式。
//語句 function f(){} //表達式 var f = function f(){}
為了避免解析上的歧義,JavaScript引擎規定,如果 function 關鍵字出現在首行,一律解析成語句。因此,JavaScript引擎看到行首是 function 關鍵字之後,認為這一段都是函數的定義,不應該以圓括號結尾,所以就報錯了。
解決方法就是不要讓 function 出現在行首,讓引擎將其理解成一個表達式。最簡單的處理,就是將其放在一個圓括號裏面。
(function(){ / * code */ }()); //或者 (function(){ /* code */ })();
上面兩種寫法都是以圓括號開頭,引擎就會認為後面跟的是一個表達式,而不是函數定義語句,所以就避免了錯誤。這就叫做“立即調用的函數表達式”(Immediately-Invoked Function Expression),簡稱IIFE。
註意,上面兩種寫法最後的分號都是必須的。如果省略分號,遇到連著的兩個IIFE,可能就會報錯。
//報錯 (function(){ /* code */}()) (function(){ /* code */}())
上面代碼的兩行之間沒有分號,JavaScript會將它們連在一起解釋,將第二行解釋為第一行的參數。
推而廣之,任何讓解釋器以表達式來處理函數定義的方法,都能產生同樣的效果,比如下面三種寫法。
var i = function(){ return 10;} true && function(){/* code */}(); 0,function(){/* code */}();
甚至像下面這樣寫,也是可以的。
!function () { /* code */ }(); ~function () { /*code */ }(); -function () { /* code */ }(); +function () { /* code */ }();
通常情況下,只對匿名韓式使用這種“立即執行的函數表達式”。它的目的有兩個:一是不必為函數命名,避免了汙染全局變量;二是IIFE內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。
// 寫法一 var tmp = newData; processData(tmp); storeData(tmp); // 寫法二 (function () { var tmp = newData; processData(tmp); storeData(tmp); }());
上面代碼中,寫法二比寫法一更好,因為完全避免了汙染全局變量。
立即調用的函數表達式(IIFE)