1. 程式人生 > >JS-立即執行函數表達式(IIFE)

JS-立即執行函數表達式(IIFE)

遞歸調用 時報 遞歸 javascrip 應該 匿名 use 歧義 true

javascript函數調用

在javascript中,每一個函數在被調用的時候都會創建一個執行上下文,在該函數內部定義的變量和函數只能在該函數內部被使用,而正是因為這個上下文,使得我們在調用函數的時候能創建一些私有變量。

  • 先聲明後調用
// 聲明:
var foo = function(){ /* code */ };
// 調用:
foo();
  • 如果想不聲明直接調用
function(){ /* code */ }(); 
// 報錯:SyntaxError: Unexpected token (
// 執行到第一個左括號‘(‘時報錯,因為函數函數應該有函數名而這裏沒有
  • 加上函數名再調用
function foo(){ /* code */ }(); 
// 報錯:SyntaxError: Unexpected token )
// 執行到倒數第一個右括號‘)‘時報錯
// 因為()是提高優先級的分組操作符,分組操作符內的表達式不能為空

使用立即執行函數(IIFE)

// 最常用的兩種寫法
(function(){ /* code */ }()); // 老道推薦寫法
(function(){ /* code */ })(); // 當然這種也可以
 
// 括號和JS的一些操作符(如 = && || ,等)可以在函數表達式和函數聲明上消除歧義
// 如下代碼中,解析器已經知道一個是表達式了,於是也會把另一個默認為表達式
// 但是兩者交換則會報錯
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
 
// 如果你不怕代碼晦澀難讀,也可以選擇一元運算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
 
// 你也可以這樣
new function(){ /* code */ }
new function(){ /* code */ }() // 帶參數

《立即執行函數》還是《自執行函數》

IIFE的稱謂在現在似乎已經得到了廣泛推廣(不知道是不是原文作者的功勞?),而原文寫於10年,似乎當時流行的稱呼是自執行函數(Self-executing anonymous function),接下去作者開始為了說明立即執行函數的稱呼好於自執行函數的稱呼開始據理力爭,有點咬文嚼字,不過也蠻有意思的,我們來看看作者說了些什麽。

// 這是一個自執行函數,函數內部執行的是自己,遞歸調用
function foo() { foo(); }

// 這是一個自執行匿名函數,因為它沒有函數名
// 所以如果要遞歸調用自己的話必須用arguments.callee
var foo = function() { arguments.callee(); };

// 這可能也算是個自執行匿名函數,但僅僅是foo標誌引用它自身
// 如果你將foo改變成其它的,你將得到一個used-to-self-execute匿名函數
var foo = function() { foo(); };

// 有些人叫它自執行匿名函數,盡管它沒有執行自己,只是立即執行而已
(function(){ /* code */ }());

// 給函數表達式添加了標誌名稱,可以方便debug
// 但是一旦添加了標誌名稱,這個函數就不再是匿名的了
(function foo(){ /* code */ }());

// 立即執行函數也可以自執行,不過不常用罷了
(function(){ arguments.callee(); }());
(function foo(){ foo(); }());

我的理解是作者認為自執行函數是函數內部調用自己(遞歸調用),而立即執行函數就如字面意思,該函數立即執行即可。其實現在也不用去管它了,就叫IIFE好了。

JS-立即執行函數表達式(IIFE)