JavaScript 中需要創(chuàng)建函數(shù)的話,有兩種方法:函數(shù)聲明、函數(shù)表達式,各自寫法如下:
1
2
3
4
5
6
7
|
// 方法一:函數(shù)聲明 function foo() {} // 方法二:函數(shù)表達式 var foo = function () {}; |
另外還有一種自執(zhí)行函數(shù)表達式,主要用于創(chuàng)建一個新的作用域,在此作用域內(nèi)聲明的變量不會和其它作用域內(nèi)的變量沖突或混淆,大多是以匿名函數(shù)方式存在,且立即自動執(zhí)行:
1
2
3
|
( function () { // var x = ... })(); |
此種自執(zhí)行函數(shù)表達式歸類于以上兩種方法的第二種,也算是函數(shù)表達式。
方法一和方法二都創(chuàng)建了一個函數(shù),且命名為 foo,但是二者還是有區(qū)別的。JavaScript 解釋器中存在一種變量聲明被提升(hoisting)的機制,也就是說變量(函數(shù))的聲明會被提升到作用域的最前面,即使寫代碼的時候是寫在最后面,也還是會被提升至最前面。
例如以下代碼段:
1
2
3
4
5
6
|
alert(foo); // function foo() {} alert(bar); // undefined function foo() {} var bar = function bar_fn() {}; alert(foo); // function foo() {} alert(bar); // function bar_fn() {} |
輸出結果分別是function foo() {}、undefined、function foo() {}和function bar_fn() {}。
可以看到 foo 的聲明是寫在 alert 之后,仍然可以被正確調(diào)用,因為 JavaScript 解釋器會將其提升到 alert 前面,而以函數(shù)表達式創(chuàng)建的函數(shù) bar 則不享受此待遇。
那么bar 究竟有沒有被提升呢,其實用 var 聲明的變量都會被提升,只不過是被先賦值為 undefined 罷了,所以第二個 alert 彈出了 undefined。
所以,JavaScript 引擎執(zhí)行以上代碼的順序可能是這樣的:
- 創(chuàng)建變量 foo 和 bar,并將它們都賦值為 undefined。
- 創(chuàng)建函數(shù) foo 的函數(shù)體,并將其賦值給變量 foo。
- 執(zhí)行前面的兩個 alert。
- 創(chuàng)建函數(shù) bar_fn,并將其賦值給 bar。
- 執(zhí)行后面的兩個 alert。
注:
嚴格地說,再 JavaScript 中創(chuàng)建函數(shù)的話,還有另外一種方法,稱為“函數(shù)構造法”:
1
2
|
var foo = Function( 'alert("hi!");' ); var foo = new Function( 'alert("hi!");' ); // 等同于上面一行 |
此方法以一個字符串作為參數(shù)形成函數(shù)體。但是用這種方法,執(zhí)行效率方面會打折扣,且似乎無法傳遞參數(shù),所以少用為妙。