js之函数柯里化
函数柯里化是js函数式编程的一项重要应用,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。假设我们要计算一个表达式如下
function add(a,b,c){ return a+b+c; } add(1,2,3);//直接调用输出 add(1)(2)(3);//参数分开调用输出
第一种是我们常见的,第二种参数分开调用不常见,但我们也能实现他 如下
function add(a){ return function(b){ return function(c){ return a + b + c; } } }
显然 ,这样的写法很受参数个数的限制,比较不现实,那么我们需要一个通用函数来实现以上函数功能,这就是基础版的函数柯里化
var curry = function(func){ var args = [].slice.call(arguments,1); // 首先我们对通用函数截取参数 return function(){ var newArgs = args.concat([].slice.call(arguments)); //将每次添加的函数连接起来 return func.apply(this,newArgs); //将此函数的数组赋给目标函数 并传入参数 } } function sub(a,b){ return a-b; } var subcurry = curry(sub,5); console.log(subcurry(3));
此函数能实现传入不同函数,即在curry(sub,5,3)直接传入参数,或者向上面一样再次传参,或许细心的人已经看出来了,这不就是上面第二种写法,这的确是这样的,因为他还不能实现subcurry(5)(3);这样的操作,别急,这只是让你熟悉下柯里化的过程,其实柯里化的核心就是在自我简化,当一个函数需要多个参数时,我们可以层层简化,使得我们的参数变换更随意,虽然一定程度上让代码更复杂了。接下来是改进版
function add(a,b){ return a + b; } var currys = function(fn,args = []){ var length = fn.length; //计算期望函数的参数长度 args =args; //利用闭包特性保存参数 return function(){ newArgs = [].slice.call(arguments); //将自身函数参数赋给新参数 [].push.apply(newArgs,args); //将上回保留的参数push进新的数组 if(newArgs.length<length){ //判断当前函数的参数是否与期望函数参数一致 return curry.call(this,fn,newArgs); //如果不够,递归调用 }else{ return fn.apply(this,newArgs); // 如果够,就执行期望函数 } } } var addcurry = currys(add); console.log(addcurry(1)(2));
这里首先用addcurry绑定add函数,然后在进行传参,每执行一次就传入一个参数,直到所有参数传入完成就会执行期望函数 add。
当然,这只是一个改进版的通用柯里,他限制与特定的参数,如果想要不限定参数,则需要进一步修改,这里就不做出过多解释,可以自己去百度,因为这里需要自己去多琢磨才能搞懂,而不是看一篇博客就能搞懂,这里给出一到面试题
实现一个add方法,使得计算结果能满足一下表达式
add(1)(2)(3 ) =6;
add(1,2,3)(4)=10;
add(1)(2)(3)(4)(5) =15;
这里由于要将进行参数个数不确定计算,这里就要在函数内部重写toSting方法或者valueOf方法(这两个方法都是Object原型上的,一个是返回一个对象的值,默认是本身,一个是返回对象字符串)