JavaScript 函数柯里化
■设计思路
函数合成是把多个单一参数函数合成一个多参数函数的运算。例如,a(x)和b(x)组合为a(b(x)),则合成为f(a,b,X)。注意,这里的a⑻和b(x)都只能接受一个参数。如果接受多个参数,如a(x,y)和b(a,b,c),那么函数合成就会比较麻烦。
这时就要用到函数柯里化。所谓柯里化,就是把一个多参数的函数,转化为单一参数函数。有了柯里化运算之后,我们就能做到所有函数只接受一个参数。
【实现方法】
先用传递给函数一部分参数来调用它,让它返回一个函数,然后再去处理剩下的参数。也就是说,把多参数的函数分解为多步操作的函数,以实现每次调用函数时,仅需要传递更少或单个参数。例如,下面是一个简单的求和函数add()。
var add = function (x, y) {
return x + y;
}
每次调用add(),需要同时传入两个参数,如果希望每次仅需传入一个参数,可以这样进行柯里化。
var add = function (x) { //柯里化
return function (y) {
return x + y
}
}
console.log(add(2)(6)); //8,连续调用
var addl = add(200);
console.log(addl(2)); //202,分步调用
函数add()接受一个参数,并返回一个函数,这个返回的函数可以再接受一个参数,并返回两个参数之和。从某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的函数式运算方法。柯里化在DOM的回调中非常有用。
■实例设计
设想curry可以接受一个函数,即原始函数,返回的也是一个函数,即柯里化函数。这个返回的柯里化函数在执行的过程中,会不断地返回一个存储了传入参数的函数,直到触发了原始函数执行的条件。例如,设计一个add()函数,计算两个参数之和。
var add = function (x, y) {
return x + y;
}
柯里化函数:
var curryAdd = curry(add)
这个add需要两个参数,但是执行curryAdd时,可以传入更少的参数,当传入的参数少于add需要的参数时,add函数并不会执行,curryAdd就会将这个参数记录下来,并且返回另外一个函数,这个函数可以继续执行传入参数。如果传入参数的总数等于add需要参数的总数,就执行原始参数,返回想要的结果。如果没有参数限制,最后根据空的小括号作为执行原始参数的条件,则返回运算结果。
【实现代码】
//柯里化函数
function curry(fn) {
var _argLen = fn. length; //记录原始函数的形参个数
var _args = [].slice.call (arguments, 1); //把传入的第2个及以后参数转换为数组
function wrap () { //内部函数
//把当前参数转换为数组,与前面参数进行合并
_args = _args.concat([].slice.call(arguments));
function act() { //参数处理函数
//把当前参数转换为数组,与前面参数进行合并
—args = _args.concat([].slice.call(arguments));
//如果传;C参数总和大于等于原始参数的个数,触发执行条件
if ( ( _argLen == 0 && arguments.length == 0) ||
(_argLen > 0 && _args.length >= _argLen) ) {
//执行原始函数,并把^次传入参数传入进€,返回执行结果,停止curry return fn•apply(null, _args);
}
return arguments.callee;
}
//如果传入参数大于等于原始函数的参数个数,即触发了执行条件
if ( (_argLen == 0 && arguments.length ==0 ) ||
(_argLen > 0 && _args.length >= —argLen) ) {
//执行原始函数,并把^次传入参数传入进去,返回执行结果,停止curry return fn.apply(null, _args);
}
act.toString = function () {//定义处理函数的字符串表示为原始函数的字符串表示 return fn.toString ();
}
return act; //返回处理函数
}
return wrap; //返回 curry 函数
【应用代码】
应用函数无形参限制。
设计求和函数,没有形参限制,柯里化函数将根据空小括号作为最后调用原始函数的条件。
//求和函数,参数不限
var add= function () {//把参数转换为数组,然后调用数组的reduce方法
//迭代所有参数值,返回最后汇总的值
return [].slice.call(arguments).reduce(function (a, b) {
//如果元素的值为数值,则参与求和运算,否则设置为0,跳过非数字的值
return (typeof a == "number" ? a : 0) + (typeof b == "mumber" ? b : 0);
})
}
//柯里化函数
var curried = curry(add);
console.log(curried(1)(2)(3)()); //6
var curried = curry(add);
console.log(curried(1, 2, 3)(4)()); //10
var curried = curry(add,1);
console.log(curried(1, 2)(3)(3)()); //10
var curried = curry(add,1,5);
console.log(curried(1, 2, 3, 4)(5)()); //21
应用函数有形参限制。
设计求和函数,返回3个参数之和。
var add = function (a,b,c) { //求和函数,3个参数之和
return a + b+c;
}
//柯里化函数
var curried = curry(add,2)
console.log(curried(1)(2)); //5
var curried = curry(add,2,1)
console.log(curried(2)); //5
var curried = curry(add)
console.log(curried(1)(2)(6)); //9
var curried = curry(add)
console.log(curried(1, 2, 6)); //9
点击加载更多评论>>