什么是柯里化?计算机科学中的官方术语柯里化(英语:Currying),又译为Currying或Currying,是将一个接受多个参数的函数改造为接受一个参数(原函数的第一个参数)的函数,并返回一个新的接受剩余参数并返回结果的函数。该技术由ChristopherStrachey以逻辑学家HaskellGary的名字命名,尽管它是由MosesSch?nfinkel和GottlobFrege发明的。直觉上,柯里化表示如果你修复了一些参数,你会得到一个函数来接受其余的参数。在理论计算机科学中,柯里化提供了一种在简单的理论模型(例如仅接受单个参数的lambda演算)中研究具有多个参数的函数的方法。函数柯里化的对偶是Uncurrying,一种使用匿名单参数函数实现多参数函数的方法。方便地理解柯里化的概念非常简单。只传递一部分参数给函数调用,让其返回一个函数处理剩下的参数。如果我们需要实现一个函数来求三个数的和:functionadd(x,y,z){returnx+y+z;}console.log(add(1,2,3));//6varadd=function(x){returnfunction(y){returnfunction(z){returnx+y+z;}}}varaddOne=add(1);varaddOneAndTwo=addOne(2);varaddOneAndTwoAndThree=addOneAndTwo(3);console.log(addOneAndTwoAndThree);这里我们定义了一个add函数,它接受一个参数并返回一个新函数。调用add之后,返回的函数通过闭包记住了add的第一个参数。调用一次有点麻烦,但是我们可以使用一个特殊的curry辅助函数(helperfunction)来使定义和调用这样的函数更加容易。使用ES6的箭头函数,我们可以这样实现上面的add:constadd=x=>y=>z=>x+y+z;似乎使用箭头功能更清晰。部分功能?我们来看这个函数:functionajax(url,data,callback){//..}有这样一个场景:我们需要向多个不同的接口发起HTTP请求,有两种方式:调用ajax()函数,传入全局URL常量。创建一个带有前缀URL参数的函数引用。下面我们创建一个新函数,它仍然在内部发起一个ajax()请求。另外,在等待接收另外两个实参的同时,我们手动将ajax()的第一个实参设置为你关心的API地址。对于第一种方法,我们可以生成如下调用方法:functionajaxTest1(data,callback){ajax('http://www.test.com/test1',data,callback);}functionajaxTest2(data,callback){ajax('http://www.test.com/test2',data,callback);}对于这两个类似的函数,我们还可以提取出如下的模式:functionbeginTest(callback){ajaxTest1({data:GLOBAL_TEST_1,},callback);}相信你已经看到了这种模式:我们在函数调用点(functioncall-site)将实际参数应用于(apply)形式参数。如您所见,我们在开始时仅应用了一些参数-特别是URL参数-稍后应用其余参数。上面的概念就是偏函数的定义。偏函数是减少函数参数个数的过程;这里的参数个数是指你要传入的形参个数,我们通过ajaxTest1()将原函数ajax()的参数个数从3个减少到2个。我们这样定义一个partial()函数:functionpartial(fn,...presetArgs){}}partial()function接收fn参数来表示我们部分应用的函数。然后在fn参数之后,presetArgs数组收集后面传入的实际参数,保存起来,以备后用。我们创建并返回一个新的内部函数(为了清楚起见,我们称它为partiallyApplied(..)),其中laterArgs数组收集所有参数。使用箭头函数更简洁:varpartial=(fn,...presetArgs)=>(...laterArgs)=>fn(...presetArgs,...laterArgs);这种使用偏函数的模式,我们重构了之前的代码:functionajax(url,data,callback){//..}varajaxTest1=partial(ajax,'http://www.test.com/test1');varajaxTest2=partial(ajax,'http://www.test.com/test1');再想想beginTest()这个函数,如果我们用partial()来重构它怎么办?functionajax(url,data,callback){//..}//版本1varbeginTest=partial(ajax,'http://www.test.com/test1',{data:GLOBAL_TEST_1,});//版本2varajaxTest1=partial(ajax,'http://www.test.com/test1');varbeginTest=partial(ajaxTest1,{data:GLOBAL_TEST_1,});一次传递一个我相信你已经看到了上面例子中的版本2相对于版本1的优势在于,是的,柯里化就是这样:将具有多个参数的函数一次转换为一个函数的过程。每次调用一个函数时,它只接受一个参数并返回一个函数,直到所有参数都被传递。将接受多个参数的函数转换为一次接受一个参数的函数的过程。每次调用该函数时,它只接受一个参数并返回一个接受一个参数的函数,直到所有参数都被传递。假设我们已经创建了ajax()函数curriedAjax()的柯里化版本:curriedAjax('http://www.test.com/test1')({data:GLOBAL_TEST_1,})(functioncallback(data){//做一点事});我们将这三个调用分别拆解一下,或许可以帮助我们理解整个过程:varajaxTest1=curriedAjax('http://www.test.com/test1');varbeginTest=ajaxTest1({data:GLOBAL_TEST_1,});varajaxCallback=beginTest(functioncallback(data){//dosomething});实现柯里化那么,我们如何实现自动柯里化功能呢?varcurrying=function(fn){varargs=[];returnfunction(){if(arguments.length===0){returnfn.apply(this,args);//当没有传递参数时调用这个函数}else{[].push.apply(args,arguments);//传入参数,保存起来returnarguments.callee;//返回这个函数的引用}}}调用上面的currying()函数:varcost=(function(){变种钱=0;returnfunction(){for(vari=0;i
