我們定義一個函數,一般有兩種方法
- 函數聲明
function fnName(){...};
- 函數表達式
var fn = function fnName(){...}
聲明函數后,我們可以使用fnName ()來調用這個函數
function f1(){
console.log('函數聲明')
}
f1()
//輸出:函數聲明。
var f1 = function f2(){
console.log('函數聲明')
}
f1()
//輸出:函數表達式。
那么我們可不可以直接在后面加()直接調用這個函數呢?
function f1(){
console.log('函數聲明')
}()
// 報錯 SyntaxError: Unexpected token (
var f1 = function f2(){
console.log('函數聲明')
}()
//輸出 函數聲明
為什么會這樣呢,原來,JavaScript解釋器會在默認的情況下把遇到的function關鍵字當作是函數聲明語句(statement)來進行解釋的,所以第一種寫法是有語法錯誤的。
這時我們可以總結出兩種函數聲明方式的不同
- Javascript引擎在解析javascript代碼時會'函數聲明提升'(Function declaration Hoisting)當前執行環境(作用域)上的函數聲明,而函數表達式必須等到Javascirtp引擎執行到它所在行時,才會從上而下一行一行地解析函數表達式。
- 函數表達式后面可以加括號立即調用該函數,函數聲明不可以,只能以fnName()形式調用 。
所以,要在函數體后面加括號就能立即調用,則這個函數必須是函數表達式,不能是函數聲明。
一個匿名函數想立即執行就需要把它變成一個表達式,這就是立即執行函數表達式。
(function(){alert('我是匿名函數')} ()) // 用括號把整個表達式包起來
(function(){alert('我是匿名函數')}) () //用括號把函數包起來
所以根據上面的解釋,我們知道只要能讓JavaScript引擎以「函數表達式」而不是「函數聲明」來處理匿名函數的立即執行就可以了,把語句放在()之中只是其中的一種方法而已,根據這個思路我們可以用其他方式來實現同樣的目的,比如:
!function(){alert('我是匿名函數')}() // 求反,我們不在意值是多少,只想通過語法檢查。
+function(){alert('我是匿名函數')}()
-function(){alert('我是匿名函數')}()
~function(){alert('我是匿名函數')}()
void function(){alert('我是匿名函數')}()
new function(){alert('我是匿名函數')}()
立即執行函數表達式有什么作用呢?
只有一個作用:創建一個獨立的作用域。
這個作用域里面的變量,外面訪問不到(即避免「變量污染」)。