理解 javascript 中的函數(shù)表達(dá)式與函數(shù)聲明
常用閉包的同學(xué)肯定很清楚下面一段代碼:
//通常的閉包寫(xiě)法
(function () {
...
}())
那么我們的問(wèn)題來(lái)了,為什么要在 function () {...}() 之外用圓括號(hào)包裹呢?解答這個(gè)問(wèn)題,就需要我們理解 Javascript 中函數(shù)表達(dá)式與函數(shù)聲明的概念。
函數(shù)定義帶來(lái)的錯(cuò)誤
雖然 function () {...} 看上去像是一個(gè)函數(shù)聲明,但是由于沒(méi)有函數(shù)名,它的本質(zhì)其實(shí)是一個(gè)函數(shù)表達(dá)式。我們看下規(guī)范中對(duì)于函數(shù)聲明與函數(shù)表達(dá)式的定義:

可以看出來(lái),函數(shù)聲明是必須帶有函數(shù)名的。所以在直接執(zhí)行 function () {...}() 時(shí)候會(huì)報(bào)語(yǔ)法錯(cuò)誤,原因就是函數(shù)表達(dá)式被嘗試解析為函數(shù)聲明時(shí)沒(méi)有找到函數(shù)名。

那么我們繼續(xù)嘗試寫(xiě)上函數(shù)名的情況:
function fn () {...}()

仍然會(huì)提示語(yǔ)法錯(cuò)誤,不過(guò)這次的出錯(cuò)的位置在后面 () 中的 ) 上。
先不解釋為什么,看接下來(lái)的示例:

從這個(gè)結(jié)果可以看出,函數(shù)聲明之后的 () 會(huì)被解析為分組運(yùn)算符,而不是函數(shù)調(diào)用。那么如何才能使函數(shù)執(zhí)行呢?
如何正確解析函數(shù)表達(dá)式
根據(jù)規(guī)范,函數(shù)表達(dá)式必須在 Expression 中才能進(jìn)行正確的語(yǔ)法解析。恰巧 () 在作為分組運(yùn)算符時(shí),里面的內(nèi)容會(huì)被認(rèn)為是 Expression。
(function () {...}())
(function () {...})()
上述兩種寫(xiě)法都是正確的。第一種寫(xiě)法比較清晰,函數(shù)表達(dá)式被正確解析并調(diào)用。第二種寫(xiě)法中,解析器首先處理 (function () {...}) 部分,由于分組運(yùn)算符不會(huì)對(duì)其中內(nèi)容進(jìn)行 GetValue 操作,所以在語(yǔ)句結(jié)束時(shí),其中的函數(shù)表達(dá)式被直接返回,之后的 () 則表示函數(shù)調(diào)用。
我們來(lái)簡(jiǎn)單的用一個(gè)例子表示一下:
var a = function () {...}
(a()) //形同 (function () {...}())
(a)() //形同 (function () {...})()
這個(gè)例子稍有不恰當(dāng),因?yàn)橹苯訄?zhí)行 a() 是可行的,而直接執(zhí)行 function () {...}() 則不行,原因就是上面提到的,function () {...} 被嘗試解析為函數(shù)聲明而引發(fā)了語(yǔ)法錯(cuò)誤。
其他方式
上面我們提到通過(guò) () 分組運(yùn)算符,可以將匿名函數(shù)正確的理解為函數(shù)表達(dá)式。同理,我們也可以通過(guò)許多其他的運(yùn)算符將函數(shù)表達(dá)式正確執(zhí)行。
!function () {}()
void function () {}()
+function () {}()
-function () {}()
if (function () {}()) {}
...
由于很多操作符會(huì)改變函數(shù)返回值,比如 !function () {return 0},void function () {}(),+ function () {}() 等,所以我們一般使用 () 將匿名函數(shù)包裹使其被正確解析為函數(shù)表達(dá)式。
參考文章
相關(guān)文章
js實(shí)現(xiàn)跟隨鼠標(biāo)移動(dòng)且?guī)шP(guān)閉功能的圖片廣告實(shí)例
這篇文章主要介紹了js實(shí)現(xiàn)跟隨鼠標(biāo)移動(dòng)且?guī)шP(guān)閉功能的圖片廣告,實(shí)例分析了javascript操作鼠標(biāo)事件及html元素的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
9行javascript代碼獲取QQ群成員具體實(shí)現(xiàn)
22 行 JavaScript 代碼實(shí)現(xiàn) QQ 群成員提取器,如果沒(méi)有達(dá)到效果可能原因一是QQ版本升級(jí)了,二是博客里面的代碼也有些繁瑣2013-10-10
JavaScript學(xué)習(xí)筆記之?dāng)?shù)組隨機(jī)排序
這篇文章主要介紹了JavaScript學(xué)習(xí)筆記之?dāng)?shù)組隨機(jī)排序的相關(guān)資料,需要的朋友可以參考下2016-03-03
JavaScript腳本語(yǔ)言是什么_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
JavaScript是什么?這篇文章主要介紹了一種廣泛用于客戶(hù)端Web開(kāi)發(fā)的腳本語(yǔ)言JavaScript,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
用js實(shí)現(xiàn)before和after偽類(lèi)的樣式修改的示例代碼
本篇文章主要介紹了用js實(shí)現(xiàn)before和after偽類(lèi)的樣式修改的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09
JS中國(guó)標(biāo)準(zhǔn)時(shí)間轉(zhuǎn)化為年月日時(shí)分秒'yyyy-MM-dd hh:mm:ss'的示例詳解
這篇文章主要介紹了JS中國(guó)標(biāo)準(zhǔn)時(shí)間轉(zhuǎn)化為年月日時(shí)分秒‘yyyy-MM-dd hh:mm:ss‘的相關(guān)知識(shí),通過(guò)示例代碼介紹了,Js各種時(shí)間轉(zhuǎn)換問(wèn)題(YYYY-MM-DD 時(shí)間戳 中國(guó)標(biāo)準(zhǔn)時(shí)間),需要的朋友可以參考下2024-02-02
ECMAScript6函數(shù)默認(rèn)參數(shù)
這篇文章主要介紹了ECMAScript6函數(shù)默認(rèn)參數(shù)的相關(guān)資料,需要的朋友可以參考下2015-06-06
利用JavaScript腳本實(shí)現(xiàn)滾屏效果的方法
這篇文章主要介紹了利用JavaScript腳本實(shí)現(xiàn)滾屏效果的方法,即一個(gè)公告欄顯示般的效果,需要的朋友可以參考下2015-07-07
淺談JavaScript find 方法不支持IE的問(wèn)題
下面小編就為大家?guī)?lái)一篇淺談JavaScript find 方法不支持IE的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09

