zl程序教程

您现在的位置是:首页 >  其它

当前栏目

javascriptcurrying返回函数的函数

函数 返回
2023-06-13 09:14:14 时间
最早期的curry函数有点多态的意味,就是根据函数参数在内部选用分支:
复制代码代码如下:

//http://www.openlaszlo.org/pipermail/laszlo-user/2005-March/000350.html
//★★On8Mar2005,at00:06,SteveAlbinwrote:

functionadd(a,b){

if(arguments.length<1){

returnadd;

}elseif(arguments.length<2){

returnfunction(c){returna+c}

}else{

returna+b;

}

}



varmyadd=add(2);

vartotal=myadd(3);


日本的一个先行者可能在未搞清arguments也能用Array的原生方法转换为数组的时候,用非常复杂的正则与eval搞出一个更接近现代currying意味的函数。

复制代码代码如下:

functioncurry(fun){

if(typeoffun!="function"){

thrownewError("Theargumentmustbeafunction.");

}

if(fun.arity==0){

thrownewError("Thefunctionmusthavemorethanoneargument.");

}

varfunText=fun.toString();

varargs=/function.*\((.*)\)(.*)/.exec(funText)[1].split(",");

varfirstArg=args.shift();

varrestArgs=args.join(",");

varbody=funText.replace(/function.*\(.*\)/,"");

varcurriedText=

"function("+firstArg+"){"+

"returnfunction("+restArgs+")"+body+

"}";

eval("varcurried="+curriedText);

returncurried;
}

functioncurry(fun){ if(typeoffun!="function"){ thrownewError("Theargumentmustbeafunction."); } if(fun.arity==0){ thrownewError("Thefunctionmusthavemorethanoneargument."); } varfunText=fun.toString(); varargs=/function.*\((.*)\)(.*)/.exec(funText)[1].split(","); varfirstArg=args.shift(); varrestArgs=args.join(","); varbody=funText.replace(/function.*\(.*\)/,""); varcurriedText= "function("+firstArg+"){"+ "returnfunction("+restArgs+")"+body+ "}"; eval("varcurried="+curriedText); returncurried; } functionsum(x,y){ returnx+y; } functionmean3(a,b,c){ return(a+b+c)/3; } vara=curry(sum)(10)(15) alert(a)//25 varb=curry(mean3)(10)(20,30); alert(b)//20 varc=curry(curry(sum))(10)()(20); alert(c); vard=curry(curry(mean3)(10))(20)(30); alert(d);

接着是闭包的流行,与数组转换arguments的技术的发现,现代currying函数终于粉墨登场,就好像15~17世纪大航海时代的地理大发现,javascript的世界突然间开阔了许多。
复制代码代码如下:
//一个简单的现代currying函数
functioncurry(fn,scope){
varscope=scope||window;
varargs=[];
for(vari=2,len=arguments.length;i<len;++i){
args.push(arguments[i]);
};
returnfunction(){
fn.apply(scope,args);
};
}

一般的currying函数只有两重,执行情况如下,第一次执行参数不足返回内部函数,第二次执行才最终完成。不过针对这参数,我们还是可以做一些文章。看如下函数:
复制代码代码如下:
functionsum(){
varresult=0;
for(vari=0,n=arguments.length;i<n;i++){
result+=arguments[i];
}
returnresult;
}
alert(sum(1,2,3,4,5));//15

这就没有所谓的参数不足问题,传入一个参数,它也计算。但不传入参数呢?无错,区别在于有没有参数。我们可以让它不断执行自身,如果参数存在的情况下。最后在没有参数的情况下,一次过执行。换言之,前面的步骤是用于储存参数。
varsum2=curry(sum);
sum2=sum2(1)(2)(3)(4)(5);
sum2();//15
比起一般的currying函数,这有点难度。具体看注解:
复制代码代码如下:
varcurry=function(fn){//原函数的参数为函数
returnfunction(args){//内部函数的参数为数组,由于立即执行,因此直接到第三重去
//args是相对于第三重内部函数可是全局变量
varself=arguments.callee;//把自身保存起来(就是那个数组为参数的第二重函数)
returnfunction(){//这才是第二次调用的函数
if(arguments.length){//如果还有要添加的参数
[].push.apply(args,arguments);//apply把当前传入的所有参数放进args中
returnself(args);
}else{
returnfn.apply(this,args);//apply的第二参数为数组
}
}
}([]);
};

functionsum(){ varresult=0; for(vari=0,n=arguments.length;i

或者每次传入多个参数:
functionsum(){ varresult=0; for(vari=0,n=arguments.length;i

但上面的函数有不足之处,最后怎么也要放个括号,我们想只要参数足够就返回结果,多出的参数忽略。改进如下:
复制代码代码如下:
functioncurry(f){
if(f.length==0)returnf;
functioniterate(args){
if(args.length<=f.length)
returnf.apply(null,args);
returnfunction(){
returniterate(args.concat(Array.prototype.slice.call(arguments)));
};
}
returniterate([]);
}

functioncurry(f){ if(f.length==0)returnf; functioniterate(args){ if(args.length>=f.length) returnf.apply(null,args); returnfunction(){ returniterate(args.concat(Array.prototype.slice.call(arguments))); }; } returniterate([]); } functionmean3(a,b,c){return(a+b+c)/3;} varcurriedMean3=curry(mean3); alert(curriedMean3(1)(2,3));//=>2 alert(curriedMean3(1)(2)(3));//空括号无效 alert(curriedMean3()(1)()(2)()(3));//=>2 alert(curriedMean3(1,2)(3,4));//=>2(第四个参数无效)