簡介
JavaScript 的 function 主要特色有二:
- function 是 first-class object,可以像 value 一樣當作參數傳遞,也可以擴充其 property 及 method
- function 提供了 scope 的概念,在 function 中用
var
宣告變數皆會是 local variable(不同於某些語言,JavaScript 並不擁有 curly brace local scope)
Function Expression
又稱為 anonymous function,如下例:
|
|
function expression 的一個特例為 named function expression,如下:
|
|
兩者的差異是,前者 function object 的 name
property 會是空字串(Firefox & WebKit)或 undefined
(IE),後者 add.name
的值會是 “add”。
註:name
property 並非 ECMAScript 標準,但大多數環境皆可使用,特別在使用 debug 工具時可能常會用到。
另外,named function expression 不建議 assign 給另一個名稱的變數,如:var foo = function bar() {};
,此用法在部分 browser(如 IE)並未被正確實作。
我們應避免使用如同 var add = new Function('a, b', 'return a + b;');
的 constructor function,因為這種做法常會需要使用 escape character 且縮排不便,對可讀性影響很大。
Function Declaration
|
|
上述兩種定義 function 的方式在結尾部分有所不同,expression 需加上分號, declaration 則不用。除此之外,最大的差異在於 hoisting 行為…
Function Hoisting
function declaration 與 named function expression 乍看之下兩者的外觀與行為都十分接近,其實不然。如同第2章筆記提到的 hoisting 行為,不論在程式何處宣告變數,都會在幕後被 hoisted 到最頂端(僅宣告該變數,不會定義其內容,即 var foo = undefined;
)。
|
|
從上例可以很明顯看出:由於 hoisting 行為,named function expression 只有變數宣告被 hoisted,其 function 實作的部分並沒有;而 function declaration 則會將宣告及實作皆 hoisted。
Callback Function
設計 function 時應盡可能使其保持 generic,亦即不要將許多功能的實作寫死在同一個 function 中。這種需 coupling 多個動作於同一個 function 的動機,便是非常適合使用 callback 的時機。
|
|
注意 callback 的 scope
當 callback 並非 anonymous function 或 global function,而是某個 object 的 method 時,如果其中有使用 this
去 refer 其所屬的 object,會導致非預期的行為。
解法:除了傳遞 callback 之外,額外傳遞其所屬 object,並將呼叫方式改為 callback.call(callback_obj, found);
其他使用 callback 的例子
- Asynchronous Event Listener:
document.addEventListener("click", callback, false);
- Timeout:
setTimeout(callback, 1000);
Returning Function
|
|
在 init()
中包裝 returned function 會產生一個 clusure,可用於儲存 private 資料,因為這些資料只能被 returned function 存取。
Self-Defining Function
|
|
又稱 lazy function definition,用這種方式可回收舊的 function pointer 並指向新 function,即用新的實作內容覆蓋掉自己。對於某些只需執行第一次便不再用到的工作,此法非常適合使用。
Immediate Function
|
|
又稱 self-invoking function 或 self-executing function,此語法可讓 function 在定義時立刻執行,適用於只需執行一次且不再重複使用時(如初始化動作),也可以避免暫時使用的變數汙染了 global scope。
immediate function 也可以有參數及回傳值:可將 global object 作為參數傳進 function 中以便存取 global variable;也可以在完成某個複雜的運算後回傳其值並將整個 function 直接 assign 給變數。
另外一個與此 pattern 類似的是 Immediate Object Initialization,適用在初始化較繁複的一次性工作,在 init()
完成後不再存取該 object。
|
|
Function Property
由於 function 是 object,因此當然可以擁有 property。我們可以透過自訂 property 來作為運算結果的 cache,下次再被呼叫時便不必重複可能非常繁重的計算。
|
|
Configuration Object
此 pattern 在提供乾淨的 APIs 時相當有用。程式開發時,需求發生變動是很平常的事,因此可能會出現一些 function 逐漸擁有許多參數,且有些參數是 required 有些則是 optional。
|
|
我們可以將所有參數替換成一個 object 並作為唯一的參數,這麼做相較於上例擁有下列優點:
- 不需記住參數的順序
- 可以安全的略過 optional 參數
- 容易閱讀及維護
- 容易新增及移除參數
|
|
Curring
即 partial function application,當經常呼叫某個 function 且其傳入的參數大多都相同時,便適合使用 curring 技巧。使用時會先傳入部分參數給 function,並動態產生另一個新 function,如此該新 function 便能保留重複的那些參數,於是就不必每次都傳遞。
術語說明
- curring:其命名是來自數學家 Haskell Curry,指 function transformations 的過程
- unction application:實際上 function 並不是被 called 或 invoked,而是 applied。JavaScript 的 function object 有提供
Function.prototype.apply()
及Function.prototype.call()
兩個 method
|
|
實際範例
|
|
附註:書上另有 general-purpose function 可用,實作方式較為複雜,需要時可再查閱。