介紹
IIFE(Immediately Invoked Function Expression),中文名稱:立即執行函數表達式,其實IIFE最早并不叫這個名字,而是叫做Self-Executing Anonymous Function
,即自執行匿名函數。根據MDN的資料,IIFE這個說法最早由Ben Alman于2010年提出,下面我們一起來看看這個名字的來龍去脈。
2010年11月5日,Ben Alman寫下來他的著名文章:Immediately-Invoked Function Expression (IIFE),標志著IIFE這個名字的誕生。
在文章中,Ben Alman稱他是一個對待術語非常嚴謹的人,之前他多次看到Self-Executing Anonymous Function
這個說法,覺得不是很恰當,于是他提出了Immediately-Invoked Function Expression
這個說法。
IIFE到底是咋來的?
當我們定義一個函數或者一個函數表達式時,你得到的是一個名字,通過這個名字,你就可以調用這個函數。
下面這兩段代碼,第一個定義了一個普通函數,第二個定義了一個函數表達式,這兩種形式,我們都可以通過標識符foo
來調用它們。
function foo() {
console.log('I am a function');
}
const foo = function() {
console.log('I am a function expression');
};
也就是說,當javascript
解釋器遇到全局function
關鍵字,或者一個函數內部的function
關鍵字時,會將其解釋為一個函數聲明。
然而函數聲明是無法直接調用的,所以下面的寫法會導致錯誤:
function foo() {
console.log('I am a function');
}();
我們來分析一下,上面這段代碼,javascript解釋器會將其解釋為一個函數聲明,和一個分組操作符(()
), 分組操作符是用來改變運算符優先級的,里面必須有表達式才行,所以javascript解釋器會報錯。
那我們就給它一個表達式:
function foo() {
console.log('I am a function');
}(1);
這回代碼不報錯了,但是這段代碼毫無意義,這個函數并沒有執行,實際上這段代碼與下面的代碼等價:
function foo() {
console.log('I am a function');
}
(1);
它的返回值就是1,這不是我們想要的結果,我們需要函數定義后能立即被執行,那就需要我們告訴javascript解釋器,這個函數是一個表達式,而不是一個聲明,因為表達式可以立即執行,但是聲明不能。
而在javascript中,生成表達式最簡單的方式就是用()
包裹起來,于是有了下面的代碼
(function foo() {
console.log('I am a function');
});
這樣函數聲明就變成了一個函數表達式,但是這個表達式沒有名字,我們沒法調用它,我們先給它一個名字,然后通過名字調用它。
const bar = (function foo() {
console.log('I am a function');
});
bar();
這樣完全沒有問題,但是這里的bar
實在有點多余,實際上bar
和
(function foo() {
console.log('I am a function');
});
是等價的,既然bar()
可以調用函數,那么我們直接在函數表達式末尾加上()
,也可以調用這個函數,于是就有了下面的代碼,這就是IIFE的由來。
(function foo() {
console.log('I am a function');
})();
將()
寫在外層的括號內也一樣,這種方式頗得javascript專家Douglas Crockford的青睞。我本人更喜歡第一種。
(function() {
console.log('I am a function');
}());
IIFE的變種
由上面介紹可知,生成IIFE的精髓就是將函數聲明變成函數表達式
,而在javascript中,生成表達式可不止使用()
包裹起來這一種方式,還有很多其他的方式可以實現。于是IIFE也就是產生了諸多變種。
這個變種利用賦值運算符=
來實現,賦值運算符是將右側表達式的值賦值給左側變量的,所以它右側的部分被解析成了函數表達式及其調用。
const i = function() {
console.log('I am an IIFE');
}();
下面的表中使用邏輯運算符來生成表達式。
true & (function() {
console.log('I am an IIFE');
}());
還有下面這些,都是利用一元運算符來生成函數表達式。
!function(){ }();
~function(){ }();
-function(){ }();
+function(){ }();
最后來一個不為人知的,void
運算符會對其右側的表達是求值然后返回undefined
。(void expression
- 先對expression
求值,然后返回undefined
)。
void function() {
console.log('I am an IIFE');
}();
還有使用new
運算符來生成IIFE,這種方式比較少見,因為它會創建一個新的對象。
new function() {
console.log('I am an IIFE');
}();
這些方式都比較偏門了,不建議使用,只是用來幫助我們理解IIFE的。
為什么Self-Executing Anonymous Function這個名字不好?
Ben Alman
認為這個名字有兩個問題:
Self-Executing:這個名字暗示函數會調用自己,但是實際上函數是立即被執行的,而不是調用它自身。
比如下面的幾段代碼都會調用自己,但是這并不是IIFE的語義。
function foo() { foo();
const foo = function() { arguments.callee(); };
Anonymous:這個名字暗示函數是匿名的,但實際上函數可以有名字,也可以沒有名字,比如下面的例子:
(function foo() {
console.log('I am an IIFE');
})();
轉自https://www.cnblogs.com/graphics/p/18959048
該文章在 2025/7/3 9:12:40 編輯過