我們定義一個(gè)函數(shù),一般有兩種方法
- 函數(shù)聲明
function fnName(){...};
- 函數(shù)表達(dá)式
var fn = function fnName(){...}
聲明函數(shù)后,我們可以使用fnName ()來(lái)調(diào)用這個(gè)函數(shù)
function f1(){
console.log('函數(shù)聲明')
}
f1()
//輸出:函數(shù)聲明。
var f1 = function f2(){
console.log('函數(shù)聲明')
}
f1()
//輸出:函數(shù)表達(dá)式。
那么我們可不可以直接在后面加()直接調(diào)用這個(gè)函數(shù)呢?
function f1(){
console.log('函數(shù)聲明')
}()
// 報(bào)錯(cuò) SyntaxError: Unexpected token (
var f1 = function f2(){
console.log('函數(shù)聲明')
}()
//輸出 函數(shù)聲明
為什么會(huì)這樣呢,原來(lái),JavaScript解釋器會(huì)在默認(rèn)的情況下把遇到的function關(guān)鍵字當(dāng)作是函數(shù)聲明語(yǔ)句(statement)來(lái)進(jìn)行解釋的,所以第一種寫(xiě)法是有語(yǔ)法錯(cuò)誤的。
這時(shí)我們可以總結(jié)出兩種函數(shù)聲明方式的不同
- 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)用 。
所以,要在函數(shù)體后面加括號(hào)就能立即調(diào)用,則這個(gè)函數(shù)必須是函數(shù)表達(dá)式,不能是函數(shù)聲明。
一個(gè)匿名函數(shù)想立即執(zhí)行就需要把它變成一個(gè)表達(dá)式,這就是立即執(zhí)行函數(shù)表達(dá)式。
(function(){alert('我是匿名函數(shù)')} ()) // 用括號(hào)把整個(gè)表達(dá)式包起來(lái)
(function(){alert('我是匿名函數(shù)')}) () //用括號(hào)把函數(shù)包起來(lái)
所以根據(jù)上面的解釋,我們知道只要能讓JavaScript引擎以「函數(shù)表達(dá)式」而不是「函數(shù)聲明」來(lái)處理匿名函數(shù)的立即執(zhí)行就可以了,把語(yǔ)句放在()之中只是其中的一種方法而已,根據(jù)這個(gè)思路我們可以用其他方式來(lái)實(shí)現(xiàn)同樣的目的,比如:
!function(){alert('我是匿名函數(shù)')}() // 求反,我們不在意值是多少,只想通過(guò)語(yǔ)法檢查。
+function(){alert('我是匿名函數(shù)')}()
-function(){alert('我是匿名函數(shù)')}()
~function(){alert('我是匿名函數(shù)')}()
void function(){alert('我是匿名函數(shù)')}()
new function(){alert('我是匿名函數(shù)')}()
立即執(zhí)行函數(shù)表達(dá)式有什么作用呢?
只有一個(gè)作用:創(chuàng)建一個(gè)獨(dú)立的作用域。
這個(gè)作用域里面的變量,外面訪問(wèn)不到(即避免「變量污染」)。