前言 :
在 JavaScript 中,函式是物件,是 Function 的實例. 因為是 Function 實例,你可以將之傳給另一個變數參考. 例如 :
注意,在將 max 指定給 maximum 時,max 後並沒有加上 () 運算子,這表示要將 max 參考的物件指定給 maximum 參考(加上括號表示要執行函式)。將一個函式指定給變數,這看來如果覺得奇怪的話,或許下這個看來比較不奇怪 :
上面你所看到的函式撰寫方式,稱之為 函式實字(Function literal),這就像你寫下一個數值實字、物件實字或陣列實字,會產生數值或物件等 :
- var number = 10;
- var obj = { x : 10 };
- var array = [1, 2, 3];
- var func = function() {
- // do something...
- };
函式實字會產生 Function 的實例,在 JavaScript 中,無論是函式宣告或函式實字,都會產生 Function 的實例。事實上,你也可以直接指定建立 Function 的實例 :
基本上,實務上很少會直接建立 Function 實例,以上只是表示,函式確實是 Function 實例. 即然函式是物件,它就可以任意指定給其它變數,也就可以指定作為另一個函式的引數,那它就不僅能被呼叫,還可以主動要求另一個函式執行所指定的函式內容. 例如 :
上 例以 Array 為例,forEach 可以對陣列的每個元素作「某些事」,「某些事」是由你使用函式來指定,陣列會逐一將元素傳入給你指定的函式作為引數。 sort 則可以進行排序,但兩個元素的大小關係要由你告知,傳回正值表示傳入的 n1 順序上大於 n2,要排在 n2 的後面,傳回 0 表示兩個順序相 同,傳回負值表示 n1 順序上小於 n2,要排在 n2 的前面. 像這種將函式主動丟入函式作為引數,在 JavaScript 中是很常見到的應用。事實上,若不需要名稱,你也可以如下 :
你也可以從函式中傳回函式,這通常會形成閉包(Closure)綁定某些運算過後的資源,再傳回函式,這之後還會再談到應用. 以函式實字所建立的 Function 實例,在指定給別的變數前,稱為所謂的匿名函式(Anonymous function)。你可以完全不使用名稱來執行函式 :
實際上,函式實字也可以指定名稱. 例如 :
上例中,函式實字所建立的 max 名稱,似乎不能使用,事實上,這種語法適用於使用函式實字建立 Function 實例,但又需遞迴的場合. 例如 :
在一個匿名函式中,如果想取得本身實例,可以藉由 arguments 的 callee 來取得. 例如 :
函式既然是物件,本身亦可擁有特性. 例如函式有個 length 特性,代表其參數個數 :
函式也可以擁有方法,這個之後再談,你也可以在其上新增特性或方法,就如同一個普通的物件. 函式宣告與函式宣告在運用上,幾乎是相同的,但還是有細微的差別。例如,你若寫一個 f.js 檔案如下 :
- func();
- function func() {
- print('func');
- }
但如果你的f.js如下 :
- func();
- var func = function() {
- print('func');
- };
錯誤訊息告訴你,func 值是undefined. 原因在於,直譯器在載入 .js 時,會先處理所有的宣告,包括變數與函式宣告,接著再執行程式. 所以在第一個 f.js 中,是以函式宣告方式,直譯器已處理完成,因此接下來再執行時,就可以找到func 所參考的函式。 而在第二個 f.js中,僅宣告了 func 變數,直譯器處理完這個宣告後,接下來要執行程式時,範圍中可以看到 func 變數,但此時還沒有指定值給 func,所以是 undefined,因此不能完成函式的執行.
雖然不重要,但還是提一下的是,以上兩種方式,在遇到要建立函式實例時,都不會再重新直譯,但如果你以直接建構 Function 實例的方式,則每次都會針對你引數的字串再作直譯動作. 函式宣告方式所建立的函式名稱,其實也是範圍物件上的特性名稱. 例如若在全域範圍宣告 :
可以看到,func 名稱是全域物件上的特性!
沒有留言:
張貼留言