javascript中IIFE立即執(zhí)行函數(shù)表達(dá)式來龍去脈解析
介紹
IIFE(Immediately Invoked Function Expression),中文名稱:立即執(zhí)行函數(shù)表達(dá)式,其實(shí)IIFE最早并不叫這個(gè)名字,而是叫做Self-Executing Anonymous Function,即自執(zhí)行匿名函數(shù)。根據(jù)MDN的資料,IIFE這個(gè)說法最早由Ben Alman于2010年提出,下面我們一起來看看這個(gè)名字的來龍去脈。
2010年11月5日,Ben Alman寫下來他的著名文章:Immediately-Invoked Function Expression (IIFE),標(biāo)志著IIFE這個(gè)名字的誕生。
在文章中,Ben Alman稱他是一個(gè)對(duì)待術(shù)語非常嚴(yán)謹(jǐn)?shù)娜?,之前他多次看?code>Self-Executing Anonymous Function這個(gè)說法,覺得不是很恰當(dāng),于是他提出了Immediately-Invoked Function Expression這個(gè)說法。
IIFE到底是咋來的?
當(dāng)我們定義一個(gè)函數(shù)或者一個(gè)函數(shù)表達(dá)式時(shí),你得到的是一個(gè)名字,通過這個(gè)名字,你就可以調(diào)用這個(gè)函數(shù)。
下面這兩段代碼,第一個(gè)定義了一個(gè)普通函數(shù),第二個(gè)定義了一個(gè)函數(shù)表達(dá)式,這兩種形式,我們都可以通過標(biāo)識(shí)符foo來調(diào)用它們。
// 普通函數(shù)
function foo() {
console.log('I am a function');
}
// 函數(shù)表達(dá)式
const foo = function() {
console.log('I am a function expression');
};也就是說,當(dāng)javascript解釋器遇到全局function關(guān)鍵字,或者一個(gè)函數(shù)內(nèi)部的function關(guān)鍵字時(shí),會(huì)將其解釋為一個(gè)函數(shù)聲明。
然而函數(shù)聲明是無法直接調(diào)用的,所以下面的寫法會(huì)導(dǎo)致錯(cuò)誤:
function foo() {
console.log('I am a function'); // Uncaught SyntaxError: Unexpected token ')'
}();我們來分析一下,上面這段代碼,javascript解釋器會(huì)將其解釋為一個(gè)函數(shù)聲明,和一個(gè)分組操作符(()), 分組操作符是用來改變運(yùn)算符優(yōu)先級(jí)的,里面必須有表達(dá)式才行,所以javascript解釋器會(huì)報(bào)錯(cuò)。
那我們就給它一個(gè)表達(dá)式:
function foo() {
console.log('I am a function'); // Uncaught SyntaxError: Unexpected token ')'
}(1);這回代碼不報(bào)錯(cuò)了,但是這段代碼毫無意義,這個(gè)函數(shù)并沒有執(zhí)行,實(shí)際上這段代碼與下面的代碼等價(jià):
function foo() {
console.log('I am a function');
}
(1);它的返回值就是1,這不是我們想要的結(jié)果,我們需要函數(shù)定義后能立即被執(zhí)行,那就需要我們告訴javascript解釋器,這個(gè)函數(shù)是一個(gè)表達(dá)式,而不是一個(gè)聲明,因?yàn)楸磉_(dá)式可以立即執(zhí)行,但是聲明不能。
而在javascript中,生成表達(dá)式最簡(jiǎn)單的方式就是用()包裹起來,于是有了下面的代碼
(function foo() {
console.log('I am a function');
});這樣函數(shù)聲明就變成了一個(gè)函數(shù)表達(dá)式,但是這個(gè)表達(dá)式?jīng)]有名字,我們沒法調(diào)用它,我們先給它一個(gè)名字,然后通過名字調(diào)用它。
const bar = (function foo() {
console.log('I am a function');
});
bar(); // I am a function這樣完全沒有問題,但是這里的bar實(shí)在有點(diǎn)多余,實(shí)際上bar和
(function foo() {
console.log('I am a function');
});是等價(jià)的,既然bar()可以調(diào)用函數(shù),那么我們直接在函數(shù)表達(dá)式末尾加上(),也可以調(diào)用這個(gè)函數(shù),于是就有了下面的代碼,這就是IIFE的由來。
(function foo() {
console.log('I am a function');
})();將()寫在外層的括號(hào)內(nèi)也一樣,這種方式頗得javascript專家Douglas Crockford的青睞。我本人更喜歡第一種。
(function() {
console.log('I am a function');
}());IIFE的變種
由上面介紹可知,生成IIFE的精髓就是將函數(shù)聲明變成函數(shù)表達(dá)式,而在javascript中,生成表達(dá)式可不止使用()包裹起來這一種方式,還有很多其他的方式可以實(shí)現(xiàn)。于是IIFE也就是產(chǎn)生了諸多變種。
這個(gè)變種利用賦值運(yùn)算符=來實(shí)現(xiàn),賦值運(yùn)算符是將右側(cè)表達(dá)式的值賦值給左側(cè)變量的,所以它右側(cè)的部分被解析成了函數(shù)表達(dá)式及其調(diào)用。
const i = function() {
console.log('I am an IIFE');
}();下面的表中使用邏輯運(yùn)算符來生成表達(dá)式。
true & (function() {
console.log('I am an IIFE');
}());還有下面這些,都是利用一元運(yùn)算符來生成函數(shù)表達(dá)式。
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();最后來一個(gè)不為人知的,void運(yùn)算符會(huì)對(duì)其右側(cè)的表達(dá)是求值然后返回undefined。(void expression - 先對(duì)expression求值,然后返回undefined)。
void function() {
console.log('I am an IIFE');
}();還有使用new運(yùn)算符來生成IIFE,這種方式比較少見,因?yàn)樗鼤?huì)創(chuàng)建一個(gè)新的對(duì)象。
new function() {
console.log('I am an IIFE');
}();這些方式都比較偏門了,不建議使用,只是用來幫助我們理解IIFE的。
為什么Self-Executing Anonymous Function這個(gè)名字不好?
Ben Alman認(rèn)為這個(gè)名字有兩個(gè)問題:
Self-Executing:這個(gè)名字暗示函數(shù)會(huì)調(diào)用自己,但是實(shí)際上函數(shù)是立即被執(zhí)行的,而不是調(diào)用它自身。
比如下面的幾段代碼都會(huì)調(diào)用自己,但是這并不是IIFE的語義。
// 遞歸調(diào)用自身
function foo() { foo();
// 使用arguments.callee調(diào)用自身
const foo = function() { arguments.callee(); };Anonymous:這個(gè)名字暗示函數(shù)是匿名的,但實(shí)際上函數(shù)可以有名字,也可以沒有名字,比如下面的例子:
// 有名字的IIFE
(function foo() {
console.log('I am an IIFE');
})();參考
大家有時(shí)間可以去拜讀Ben Alman的原文,大佬寫的東西就是不一樣,通俗易懂,是我輩楷模!
到此這篇關(guān)于javascript中IIFE(立即執(zhí)行函數(shù)表達(dá)式)到底是咋來的?的文章就介紹到這了,更多相關(guān)javascript中IIFE(立即執(zhí)行函數(shù)表達(dá)式)到底是咋來的??jī)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用原生javascript創(chuàng)建通用表單驗(yàn)證——更鋒利的使用dom對(duì)象
使用原生javascript創(chuàng)建通用表單驗(yàn)證——更鋒利的使用dom對(duì)象,學(xué)習(xí)js的朋友可以參考下。2011-09-09
JavaScript實(shí)現(xiàn)簡(jiǎn)易輪播圖最全代碼解析(ES6面向?qū)ο?
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)易輪播圖最全代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
使用Bootstrap typeahead插件實(shí)現(xiàn)搜索框自動(dòng)補(bǔ)全的方法
這篇文章主要介紹了使用Bootstrap typeahead插件實(shí)現(xiàn)搜索框自動(dòng)補(bǔ)全的方法的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
layui動(dòng)態(tài)渲染生成左側(cè)3級(jí)菜單的方法(根據(jù)后臺(tái)返回?cái)?shù)據(jù))
今天小編就為大家分享一篇layui動(dòng)態(tài)渲染生成左側(cè)3級(jí)菜單的方法(根據(jù)后臺(tái)返回?cái)?shù)據(jù)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09
淺談javascript中的instanceof和typeof
這篇文章主要簡(jiǎn)單介紹了javascript中的instanceof和typeof的相關(guān)資料,需要的朋友可以參考下2015-02-02
javascript完美拖拽的實(shí)現(xiàn)方法
這篇文章介紹了javascript完美拖拽的實(shí)現(xiàn)方法,有需要的朋友可以參考一下2013-09-09
Openlayers實(shí)現(xiàn)測(cè)量功能
這篇文章主要為大家詳細(xì)介紹了Openlayers實(shí)現(xiàn)測(cè)量功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
js計(jì)算兩個(gè)日期間的天數(shù)月的實(shí)例代碼
本文通過實(shí)例代碼給大家介紹了基于js計(jì)算兩個(gè)日期間的天數(shù)月,文中還通過一段代碼給大家簡(jiǎn)單說明了js計(jì)算兩個(gè)日期差的方法,感興趣的朋友跟隨小編一起看看吧2018-09-09

