函数柯里化
1.什么是柯里化
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。(百度百科搜一下就有)。
从一个普通函数得到一个柯里化函数的过程叫做函数的柯里化,返回的函数称为经过柯里化的函数。
函数柯里化的技术来自于一种编程思想,就是一个复杂的问题可以通过分步的方式来求解,分步可以保证代码逻辑的清晰易懂。
2.举个例子
function add_1(a,b,c){//普通函数 return a+b+c } console.log(add_1(1,2,3)) function add_2(a,b){//柯里化函数 return function(c){ return a+b+c } } console.log(add_2(1,2)(3)) function add_3(a){//柯里化函数 return function(b){ return function(c){ return a+b+c } } } console.log(add_3(1)(2)(3)) function curry(func){//函数的柯里化过程 return function(a,b){ return function(c){ return func(a,b,c) } } } function curry2(func){//函数的柯里化过程 return function(a){ return function(b){ return function(c){ return func(a,b,c) } } } } var add_2=curry(add_1) var add_3=curry2(add_1)
我们可以通过分步的return来实现参数的分步传递,将add_1这个普通函数变为add_2或者add_3的过程称为函数的柯里化。可以预见随着传参的不断增加,柯里化过程就要不断的增加,是否可以从curry1,curry2这两个柯里化过程中得出一个通用的函数呢?这就是柯里化函数的通用式。
柯里化函数的运行过程其实是一个参数的收集过程,我们将每一次传入的参数收集起来,最后传给函数执行。
function add_n(func,args){//func是表示处理函数;args表示所有参数 let length=func.length;//函数的形参个数,决定了要柯里化的次数 var args=args || [];//柯里化时依次收集的参数存储变量,包含了所有已收集的传参 return function(){ let _args=Array.from(arguments);//收集柯里化时函数参数 [].push.apply(_args,args);//将本轮柯里化运行时的参数添加到已收集的参数数组 if(_args.length<length){//如果参数未收集完,即已收集的参数个数小于函数的形参个数时,递归调用 return add_n.call(this,func,_args); } //当全部参数收集完成时,将所有参数传入函数中执行 return func.apply(this,_args) } } var test=function(a,b,c){ return a+b+c } var test_curry1=add_n(test) var test_curry2=add_n(test,[1]) test_curry1(1)(2)(3) //6 test_curry2(2)(3) //6
3.实际的应用场景
理解了柯里化的过程,就要注意柯里化的思想更为重要,可以用来拆分逻辑。一个关于校验的例子:
function check(partner,str){ return partner.test(str) } function check_curry(partner){ return function(str){ return partner.test(str) } } var check_phone=check_curry(/^1[34578]\d{9}$/) var check_email=check_curry(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/) //使用时较为复杂难用 check(/^1[34578]\d{9}$/,'18057192235') check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/,'123456@qq.com') //使用时更为清晰明了 check_phone('18057192235') check_email('123456@qq.com')
在柯里化的实现中,我们知道柯里化虽然具有了更多的自由度,但同时柯里化通用式里调用了arguments对象,使用了递归与闭包,因此柯里化的自由度是以牺牲了一定的性能为代价换来的。只有在情况变得复杂时,才是柯里化大显身手的时候。
参考文章:https://www.jianshu.com/p/5e1899fe7d6b