立即執行函數表達式

立即執行函數表達式

var a = 2;
(function foo() {
var a = 3;
console.log( a ); // 3
})();
console.log( a ); // 2

由於函數被包含在一對 ( ) 括號內部,因此成爲了一個表達式,通過在末尾加上另外一個
( ) 可以立即執行這個函數,比如 (function foo(){ .. })()。第一個 ( ) 將函數變成表
達式,第二個 ( ) 執行了這個函數。
這種模式很常見,幾年前社區給它規定了一個術語:IIFE,代表立即執行函數表達式
(Immediately Invoked Function Expression);
函數名對 IIFE 當然不是必須的,IIFE 最常見的用法是使用一個匿名函數表達式。雖然使
用具名函數的 IIFE 並不常見,但它具有上述匿名函數表達式的所有優勢,因此也是一個值
得推廣的實踐。

var a = 2;
(function IIFE() {
var a = 3;
console.log( a ); // 3
})();
console.log( a ); // 2

函數作用域和塊作用域

相較於傳統的 IIFE 形式,很多人都更喜歡另一個改進的形式:(function(){ .. }())。仔
細觀察其中的區別。第一種形式中函數表達式被包含在 ( ) 中,然後在後面用另一個 () 括
號來調用。第二種形式中用來調用的 () 括號被移進了用來包裝的 ( ) 括號中。
這兩種形式在功能上是一致的。選擇哪個全憑個人喜好。
IIFE 的另一個非常普遍的進階用法是把它們當作函數調用並傳遞參數進去。
例如:

var a = 2;
(function IIFE( global ) {
var a = 3;
console.log( a ); // 3
console.log( global.a ); // 2
})( window );
console.log( a ); // 2

我們將 window 對象的引用傳遞進去,但將參數命名爲 global,因此在代碼風格上對全局
對象的引用變得比引用一個沒有“全局”字樣的變量更加清晰。當然可以從外部作用域傳
遞任何你需要的東西,並將變量命名爲任何你覺得合適的名字。這對於改進代碼風格是非
常有幫助的。

這個模式的另外一個應用場景是解決 undefined 標識符的默認值被錯誤覆蓋導致的異常(雖
然不常見)。將一個參數命名爲 undefined,但是在對應的位置不傳入任何值,這樣就可以
保證在代碼塊中 undefined 標識符的值真的是 undefined:

undefined = true; // 給其他代碼挖了一個大坑!絕對不要這樣做!
(function IIFE( undefined ) {
var a;
if (a === undefined) {
console.log( “Undefined is safe here!” );
}
})();

IIFE 還有一種變化的用途是倒置代碼的運行順序,將需要運行的函數放在第二位,在 IIFE
執行之後當作參數傳遞進去。這種模式在 UMD(Universal Module Definition)項目中被廣
泛使用。儘管這種模式略顯冗長,但有些人認爲它更易理解。

var a = 2;
(function IIFE( def ) {
def( window );
})(function def( global ) {
var a = 3;
console.log( a ); // 3
console.log( global.a ); // 2
});

函數表達式 def 定義在片段的第二部分,然後當作參數(這個參數也叫作 def)被傳遞進
IIFE 函數定義的第一部分中。最後,參數 def(也就是傳遞進去的函數)被調用,並將
window 傳入當作 global 參數的值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章