用函數處理函數,來將函數組合起來運用(function composition in Javascript)
Fri, 24 Sep 2010 21:50:28 +0800今天又想到,在Javascript中可以用函數來處理一群函數,建立之間的關係,組織起來使用會比較方便。
循序、間隔執行數個函數應該是蠻簡單的,比較複雜的是嵌套,例如 a(b(c())) 這樣的形式。要怎麼建立這樣的執行關係呢?今天花了一點時間想出怎麼做:
function Compositor(){ var args = []; for (var i=0; i<arguments.length; i++) { args.push(arguments[i]); } return function(n) {//這樣會做出一個currying,來接收要處理的參數n var req = function(x) { if(args.length>0){ //如果不是最後一個函數,就遞迴下去 return x(req(args.shift())); } else { //如果是最後一個函數,就把要處理的參數n傳給他執行,結束遞迴 return x(n); } }; return req(args.shift()); }; } function a(n){return --n;}; function b(n){return n+3;}; function c(n){return n*n;}; var d = Compositor(a, b, a, c); alert(d(4));// 結果是17 alert(a(b(a(c(4)))));// 對照組,執行的結果應該要跟這個相同,都是17
測試的結果都是17。要執行的函數依序傳入,由外而內形成類似「嵌套」的關係,最後一個函數會先執行,執行結果當作參數傳給外層的函數,外層函數執行結果再傳給更外層的函數當作參數等等,循環下去。這個結構看起來也有點像decorator,其實也能拿來這樣用。
有時間再來想想還有怎樣的「關係」可以把函數組合起來使用。
2010-9-25 22:33 補充:
一直在想這樣的函數關係叫做什麼,剛剛找了一下,在wikipedia發現這個:
看起來就是我想做的東西。chain也叫做fluent interface,通常會指另一種東西,還是改掉比較好。所以我把程式中的函數名稱從Chain改成Compositor。