javascript和其他編程語(yǔ)言相比比較隨意辛慰,所以javascript代碼中充滿各種奇葩的寫(xiě)法螺垢,有時(shí)霧里看花尖昏,當(dāng)然瓷翻,能理解各型各色的寫(xiě)法也是對(duì)javascript語(yǔ)言特性更進(jìn)一步的深入理解聚凹。
( function(){…} )()和( function (){…} () )是兩種javascript立即執(zhí)行函數(shù)的常見(jiàn)寫(xiě)法,最初我以為是一個(gè)括號(hào)包裹匿名函數(shù)齐帚,再在后面加個(gè)括號(hào)調(diào)用函數(shù)妒牙,最后達(dá)到函數(shù)定義后立即執(zhí)行的目的,后來(lái)發(fā)現(xiàn)加括號(hào)的原因并非如此对妄。要理解立即執(zhí)行函數(shù)湘今,需要先理解一些函數(shù)的基本概念。
函數(shù)聲明剪菱、函數(shù)表達(dá)式摩瞎、匿名函數(shù)
函數(shù)聲明:function fnName () {…};使用function關(guān)鍵字聲明一個(gè)函數(shù),再指定一個(gè)函數(shù)名孝常,叫函數(shù)聲明旗们。
函數(shù)表達(dá)式 var fnName = function () {…};使用function關(guān)鍵字聲明一個(gè)函數(shù),但未給函數(shù)命名构灸,最后將匿名函數(shù)賦予一個(gè)變量上渴,叫函數(shù)表達(dá)式,這是最常見(jiàn)的函數(shù)表達(dá)式語(yǔ)法形式冻押。
匿名函數(shù):function () {}; 使用function關(guān)鍵字聲明一個(gè)函數(shù)驰贷,但未給函數(shù)命名,所以叫匿名函數(shù)洛巢,匿名函數(shù)屬于函數(shù)表達(dá)式括袒,匿名函數(shù)有很多作用,賦予一個(gè)變量則創(chuàng)建函數(shù)稿茉,賦予一個(gè)事件則成為事件處理程序或創(chuàng)建閉包等等锹锰。
函數(shù)聲明和函數(shù)表達(dá)式不同之處在于芥炭,一、Javascript引擎在解析javascript代碼時(shí)會(huì)‘函數(shù)聲明提升’(Function declaration Hoisting)當(dāng)前執(zhí)行環(huán)境(作用域)上的函數(shù)聲明恃慧,而函數(shù)表達(dá)式必須等到Javascirtp引擎執(zhí)行到它所在行時(shí)园蝠,才會(huì)從上而下一行一行地解析函數(shù)表達(dá)式,二痢士、函數(shù)表達(dá)式后面可以加括號(hào)立即調(diào)用該函數(shù)彪薛,函數(shù)聲明不可以,只能以fnName()形式調(diào)用 怠蹂。以下是兩者差別的兩個(gè)例子善延。
fnName();
functionfnName(){
...
}
//正常,因?yàn)椤嵘撕瘮?shù)聲明城侧,函數(shù)調(diào)用可在函數(shù)聲明之前
fnName();
varfnName=function(){
...
}
//報(bào)錯(cuò)易遣,變量fnName還未保存對(duì)函數(shù)的引用,函數(shù)調(diào)用必須在函數(shù)表達(dá)式之后
varfnName=function(){
alert('Hello World');
}();
//函數(shù)表達(dá)式后面加括號(hào)嫌佑,當(dāng)javascript引擎解析到此處時(shí)能立即調(diào)用函數(shù)
functionfnName(){
alert('Hello World');
}();
//不會(huì)報(bào)錯(cuò)豆茫,但是javascript引擎只解析函數(shù)聲明,忽略后面的括號(hào)屋摇,函數(shù)聲明不會(huì)被調(diào)用
function(){
console.log('Hello World');
}();
//語(yǔ)法錯(cuò)誤揩魂,雖然匿名函數(shù)屬于函數(shù)表達(dá)式,但是未進(jìn)行賦值操作摊册,
//所以javascript引擎將開(kāi)頭的function關(guān)鍵字當(dāng)做函數(shù)聲明肤京,報(bào)錯(cuò):要求需要一個(gè)函數(shù)名
在理解了一些函數(shù)基本概念后,回頭看看( function(){…} )()和( function (){…} () )這兩種立即執(zhí)行函數(shù)的寫(xiě)法茅特,最初我以為是一個(gè)括號(hào)包裹匿名函數(shù)忘分,并后面加個(gè)括號(hào)立即調(diào)用函數(shù),當(dāng)時(shí)不知道為什么要加括號(hào)白修,后來(lái)明白妒峦,要在函數(shù)體后面加括號(hào)就能立即調(diào)用,則這個(gè)函數(shù)必須是函數(shù)表達(dá)式兵睛,不能是函數(shù)聲明肯骇。
(function(a){
console.log(a);//firebug輸出123,使用()運(yùn)算符
})(123);
(function(a){
console.log(a);//firebug輸出1234,使用()運(yùn)算符
}(1234));
!function(a){
console.log(a);//firebug輸出12345,使用祖很!運(yùn)算符
}(12345);
+function(a){
console.log(a);//firebug輸出123456,使用+運(yùn)算符
}(123456);
-function(a){
console.log(a);//firebug輸出1234567,使用-運(yùn)算符
}(1234567);
varfn=function(a){
console.log(a);//firebug輸出12345678笛丙,使用=運(yùn)算符
}(12345678)
可以看到輸出結(jié)果,在function前面加假颇!胚鸯、+、 -甚至是逗號(hào)等到都可以起到函數(shù)定義后立即執(zhí)行的效果笨鸡,而()姜钳、坦冠!、+哥桥、-辙浑、=等運(yùn)算符,都將函數(shù)聲明轉(zhuǎn)換成函數(shù)表達(dá)式拟糕,消除了javascript引擎識(shí)別函數(shù)表達(dá)式和函數(shù)聲明的歧義判呕,告訴javascript引擎這是一個(gè)函數(shù)表達(dá)式,不是函數(shù)聲明已卸,可以在后面加括號(hào)佛玄,并立即執(zhí)行函數(shù)的代碼。
加括號(hào)是最安全的做法累澡,因?yàn)椋 ?般贼、-等運(yùn)算符還會(huì)和函數(shù)的返回值進(jìn)行運(yùn)算愧哟,有時(shí)造成不必要的麻煩。
不過(guò)這樣的寫(xiě)法有什么用呢哼蛆?
javascript中沒(méi)用私有作用域的概念蕊梧,如果在多人開(kāi)發(fā)的項(xiàng)目上,你在全局或局部作用域中聲明了一些變量腮介,可能會(huì)被其他人不小心用同名的變量給覆蓋掉肥矢,根據(jù)javascript函數(shù)作用域鏈的特性,可以使用這種技術(shù)可以模仿一個(gè)私有作用域叠洗,用匿名函數(shù)作為一個(gè)“容器”甘改,“容器”內(nèi)部可以訪問(wèn)外部的變量,而外部環(huán)境不能訪問(wèn)“容器”內(nèi)部的變量灭抑,所以( function(){…} )()內(nèi)部定義的變量不會(huì)和外部的變量發(fā)生沖突十艾,俗稱“匿名包裹器”或“命名空間”。
JQuery使用的就是這種方法腾节,將JQuery代碼包裹在( function (window,undefined){…jquery代碼…} (window)中忘嫉,在全局作用域中調(diào)用JQuery代碼時(shí),可以達(dá)到保護(hù)JQuery內(nèi)部變量的作用案腺。
轉(zhuǎn)載自:http://www.cnblogs.com/chris-oil/p/4862083.html