简介
与函数绑定紧密相关的主题是函数柯里化(function currying),它用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。请看以下例子。
柯里化写法(简单)
function add(num1, num2) {
return num1 + num2;
}
function curryadd(num3){
return add(5,num3)
}
curryadd(3);//8;
首先这个其实就是函数柯里化的雏形。不过,我们工作中不可能这么使用。或者有的同学对官方的这个例子不是太懂。那就写一个更为简单的例子
function add2(num1){
return function(num2){
return num1+num2;
}
}
add2(1)(2);//3
相信看这个例子就更为简单,那么又该如何把它改造的更好?因为它使用起来特别麻烦。不过这就是柯里化。那么柯里化又该如何书写,怎么写更好?请继续往下读
柯里化写法(动态)
柯里化的写法,一般分为柯理化函数与功能函数。也就是两个函数。那么对于柯里化函数,它只相当于对功能函数的又一次封装。
//这里是功能方法
function add(num1, num2) {
return num1 + num2;
}
//这里是柯里化函数
function curry(fn){
//对内部传递的参数进行保留值。
var args = [].slice.call(arguments,1); //将add方法除外的其它参数保留下来。
return function(){
var innerArgs = [].slice.call(); //将内部的参数放在arr中
[].push.apply(args,innerArgs); //将外部的数据添加到 args数组中,因为闭包,可以继续访问
return fn.apply(this,args);//进行运算
}
}
var curryfn = curry(add,2); //对add方法进行封装.形成新的方法
console.log(curryfn(1));//这个函数是可以传递参数的 这里传进的1就是在函数中通过innerArgs接收的。
改造add方法
以上方法中,其实已经解决了前面的问题,不过这里存在一个问题,就是这里面的参数是固定的,原因是因为定义的add方法,里面参数是固定的.
我们可以改造add方法:其实就是通过for循环将传递的参数全部进行计算即可.
function add(){
var res = 0;
for (var i = 0; i < arguments.length; i++) {
res += arguments[i];
};
return res;
}
var currayfn = curray(add,2,3,4);
currayfn(7,8,9);//35
currayfn();//9
可以发现这里已经将参数扩展了很多,效果比以前是好了许多。在这里面我们可以看到在实现currayfn这个方法时,curray(add,2,3,4) 第二个以后的参数 以及调用currayfn()的参数都是可写可不写.极大的方便了我们的工作.
升级柯里化方法
我们可以看一下如果代码写到这里说明我们已经对柯里化或者对我们之前的闭包已经很熟悉了,不过我们的扩展性并没有完全发挥到极致.我们可以尝试以下一种写法.
curray(add,1,2)(3,4)(2)();
function curry(fn){
//对内部传递的参数进行保留值。
var args = [].slice.call(arguments,1);
//将add方法除外的其它参数保留下来。
var newfn = function(){
if(arguments.length == 0){
//没有参数时,对args进行加法运算
return fn.apply(this,args)
}else{
//有参数时,将数据添加到外部数组中
[].push.apply(args,arguments)
//将自身这个柯里化函数重新返回可以连续执行.
return newfn;
}
}
return newfn;
}
//第一种写法
curray(add,1,2)(3,4)(2)();
//第二种写法
var currayadd = curray(add);
currayadd(1)
currayadd(2)
currayadd(3)
currayadd(4)
currayadd(2)
currayadd()//只有在调用函数里面不传参时,才能进行累加
这里面将匿名函数改写成了定义式写法,原因是因为递归.(可以选择匿名函数,返回arguments.callee即可)
递归:
1.每次如果有参数就添加到外部的数组中
2.每次curray后面调用一次就要返回一个新的柯里化函数
讨论一下
1.最后一种写法,里面的参数可以无限多个,而且有个好处就是,它是将所有的数字每次调用都添加到数组中,当最后调用时无参数才执行.curray(add,1,2)(3,4)(2)().
2.如果按照我们最初的写法进行计算效果如:sum(sum(sum(sum(1,2),3),4),2)
a).能够明显的感觉到代码质量比较低,同时函数调用时,需要重复不断的写函数名称.同时,它在调用函数sum(x,y)那么就会执行一次,里面的函数就会进行一次计算.
b).当代码量少的情况下,使用最初的sum会方便很多.当数据量非常大时,我们使用下面的写法无论从代码量,写法,以及性能上方便许多:
3.这里只是加法运算的柯里化,那么柯里化是一种思想,适用性非常广泛,下节课我们可以讨论一下柯里化的适用场景.
总结:
总之柯里化的原理是非常简单的,重点在于应用.后面会继续分享柯里化的更多用法.不过重点就在于开始时它的基本理念,一定要理解,当函数被调用时,返回的函数还需要设置一些传入的参数