JavaScript 函數合成
■設計思路
在函數式編程中,經常見到如下表達式運算:
a(b(c(x)));
這是“包菜式”多層函數調用,但不是很優(yōu)雅。為了解決函數多層調用的嵌套問題,我們需要用到函數合成。函數合成的語法形式如下:
var f = compose (a, b, c); //合成函數
f (x);
例如:
var compose = function (f, g) { //兩個函數合成
return function (x) {
return f(g (x));
};
};
var add = function (x) { return x + 1;} //加法運算
var mul = function (x) { return x * 5;} //乘法運算
compose (mul, add) (2) ; //合并加法運算和乘法運算,返回15
在上面的代碼中,compose函數的作用就是組合函數,將函數串聯(lián)起來執(zhí)行,將多個函數組合起來,一個函數的輸出結果是另一個函數的輸入參數,一旦第一個函數開始執(zhí)行,就會像多米諾骨牌一樣 推導執(zhí)行了。
■實例設計
下面來完善compose實現,實現無限函數合成。設計思路:既然函數像多米諾骨牌式的執(zhí)行,可以使用遞歸或迭代,在函數體內不斷地執(zhí)行arguments中的函數,將上一個函數的執(zhí)行結果作為下一個執(zhí)行函數的輸入參數。
【實現代碼】
//函數合成,從右到左合成函數
var compose = function () {
var _arguments = arguments; //緩存外層參數
var length = _arguments. length; //緩存長度
var index = length; //定義游標變量
//檢測參數,如果存在非函數參數,則拋出異常
while (index--) {
if (typeof —arguments[index] !== 'function') {
throw new TypeError (’ 參數必須為函數!');
}
}
return function () {
var index = length-1; //定位到最后一個參數下標
//如果存在2個及以上參數,則調用最后一個參數函數,并傳入內層參數
//否則直接返回第1個參數函數
var result = length ?_arguments[index].apply(this, arguments) : arguments[0];
//迭代參數函數
while ( index——){
//把右側函數的執(zhí)行結果作為參數傳給左側參數函數,并調用
result = —arguments[index]?call(this, result);
}
return result; //返回最左側參數函數的執(zhí)行結果
}
}
//反向函數合成,即從左到右合成函數
var composeLeft = function () {
return compose.apply(null, [].reverse.call ( arguments));
}
【應用代碼】
在上面的實現代碼中,composeO函數是根據參數順序,從右到左進行合成,當然也可以把參數函數按從左到右進行合成,實現代碼參考composeLeft()函數;同時在compose體內添加了一層函數的校驗,允許傳遞一個或多個參數。
var add = function (x) { return x + 5; } //加法運算
var mul = function (x) { return x * 5; } //乘法運算
var sub = function (x) { return x - 5; } //減法運算
var div = function (x) { return x / 5; } //除法運算
var fn = compose(add, mul, sub, div);
console.log (fn (50) ) ; //返回30
var fn = compose(add, compose(mul, sub, div));
console.log (fn (50) ) ; //返回30
var fn = compose(compose(add, mul), sub, div);
console.log (fn (50) ) ; //返回30
上面幾種組合方式都可以返回30。注意,排列順序要保持一致。
點擊加載更多評論>>