JavaScript 函数合成
■设计思路
在函数式编程中,经常见到如下表达式运算:
a(b(c(x)));
这是“包菜式”多层函数调用,但不是很优雅。为了解决函数多层调用的嵌套问题,我们需要用到函数合成。函数合成的语法形式如下:
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函数的作用就是组合函数,将函数串联起来执行,将多个函数组合起来,一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行,就会像多米诺骨牌一样 推导执行了。
■实例设计
下面来完善compose实现,实现无限函数合成。设计思路:既然函数像多米诺骨牌式的执行,可以使用递归或迭代,在函数体内不断地执行arguments中的函数,将上一个函数的执行结果作为下一个执行函数的输入参数。
【实现代码】
//函数合成,从右到左合成函数
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——){
//把右侧函数的执行结果作为参数传给左侧参数函数,并调用
result = —arguments[index]•call(this, result);
}
return result; //返回最左侧参数函数的执行结果
}
}
//反向函数合成,即从左到右合成函数
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。注意,排列顺序要保持一致。
点击加载更多评论>>