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