|
|
|
|
|
我今天看到一個創(chuàng)建String
原型對象的函數(shù),它的結(jié)構(gòu)是(function(){...})()
這個樣子,如下代碼所示:
/* 創(chuàng)建 replaceAll 函數(shù) */
(function(){
String.prototype.replaceAll = function(s1,s2){
return this.replace(new RegExp(s1,"gi"),s2); //g全局 i忽略大小寫
};
})();
因為有了上面的函數(shù),我們就可以在程序中使用str.replaceAll()
這個方法了,這里是用它來實(shí)現(xiàn)字符全替換的功能。
很多人不明白的是,(function(){...})()
是個什么函數(shù)結(jié)構(gòu)?它是怎樣運(yùn)行的?
(function(){...})()是立即執(zhí)行函數(shù)
其實(shí),(function(){...})()是一個立即執(zhí)行函數(shù),也叫立即調(diào)用IIFE(Immediately Invoked Function Expression)。
立即執(zhí)行函數(shù)還有另一個寫法: (function(){...}())
,但它與(function(){...})()
沒有任何區(qū)別。
我們都知道傳統(tǒng)的定義函數(shù)是這樣:
function foo(){...} //這是定義,只是讓解釋器知道其存在,不會運(yùn)行
foo(); //這是語句,解釋器遇到語句會運(yùn)行它
為什么要IIFE呢? 1:傳統(tǒng)的方法啰嗦。 2:傳統(tǒng)的方法污染全局命名空間。
那么我們這么寫 function foo(){...}();
行么?不行,為啥,因為function foo(){...}
這部分只是聲明,對解釋器來說,像是你寫了串字符串“function foo(){...}”,它需要的是解析函數(shù),可以用比如eval()
來執(zhí)行它才可以。所以把()
直接放聲明后邊是不行的,錯誤語法!
然而,我們距離成功相當(dāng)接近,只需要把函數(shù)聲明變成函數(shù)表達(dá)式就可以了。方法非常多,最常見的方法是用一對()
包裹起來:(function foo(){...})();
這就等價于
var foo= function(){...};
foo();
當(dāng)然,還有很多別的方法可以把聲明變成表達(dá)式:
!function foo(){...}();
+function foo(){...}();
void function() {...}();
(function(){...})()是如何傳值的?
需要全局對象的時候,可以這么傳, 舉例:
void function(global){
console.log("a's value is: "+global.aa); //可以獲取全局對象中aa的值
}(this)
或者
var aa=10;
(function(a){
console.log("hello world"+a);
})(aa);
JavaScript立即調(diào)用函數(shù)詳解
立即調(diào)用的函數(shù)表達(dá)式(IIFE)是一種在創(chuàng)建函數(shù)后立即執(zhí)行函數(shù)的方法。
IIFE非常有用,因為它們不會污染全局對象,而且它們是隔離變量聲明的簡單方法。
這是定義 IIFE 的語法:
(function() {
/* */
})()
IIFE 也可以用箭頭函數(shù)定義:
(() => {
/* */
})()
我們基本上在括號內(nèi)定義了一個函數(shù),然后我們追加()
以執(zhí)行該函數(shù):(/* function */)()
。
那些環(huán)繞的括號實(shí)際上是使我們的函數(shù)在內(nèi)部被視為表達(dá)式的原因。否則,函數(shù)聲明將無效,因為我們沒有指定任何名稱:
函數(shù)聲明需要一個名字,而函數(shù)表達(dá)式則不需要。
你也可以將調(diào)用括號放在表達(dá)式括號內(nèi),沒有區(qū)別,只是樣式偏好:
(function() {
/* */
}())
(() => {
/* */
}())
使用一元運(yùn)算符的替代語法
你可以使用一些更奇怪的語法來創(chuàng)建 IIFE,但它在現(xiàn)實(shí)世界中很少使用,并且它依賴于使用任何一元運(yùn)算符,(不適用于箭頭功能):
-(function() {
/* */
})()
+(function() {
/* */
})()
~(function() {
/* */
})()
!(function() {
/* */
})()
命名IIFE
IIFE 也可以命名為常規(guī)函數(shù)(不是箭頭函數(shù))。這不會改變函數(shù)不會“泄漏”到全局范圍的事實(shí),并且在執(zhí)行后不能再次調(diào)用它:
(function doSomething() {
/* */
})()
以分號開頭的 IIFE
你可能會看到這個:
;(function() {
/* */
})()
這可以防止盲目連接兩個 JavaScript 文件時出現(xiàn)問題。由于 JavaScript 不需要分號,你可能會在文件的最后一行連接一些語句,從而導(dǎo)致語法錯誤。
總結(jié)
本文詳細(xì)介紹了(function(){...})()
結(jié)構(gòu)函數(shù),它是一個立即執(zhí)行函數(shù)的寫法,同時也介紹了它是如何傳值的,以及介紹了一些需要注意的問題。通過本文,相信你對立即執(zhí)行函數(shù)有了一個比較充分的了解。