javascript currying返回函数的函数

所属分类: 网络编程 / JavaScript 阅读数: 1331
收藏 0 赞 0 分享
最早期的curry函数有点多态的意味,就是根据函数参数在内部选用分支:
复制代码 代码如下:

//http://www.openlaszlo.org/pipermail/laszlo-user/2005-March/000350.html
// ★★On 8 Mar 2005, at 00:06, Steve Albin wrote:

function add(a, b) {

if (arguments.length < 1) {

return add;

} else if (arguments.length < 2) {

return function(c) { return a + c }

} else {

return a + b;

}

}



var myadd = add( 2 );

var total = myadd(3);


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

复制代码 代码如下:

function curry(fun) {

if (typeof fun != 'function') {

throw new Error("The argument must be a function.");

}

if (fun.arity == 0) {

throw new Error("The function must have more than one argument.");

}

var funText = fun.toString();

var args = /function .*\((.*)\)(.*)/.exec(funText)[1].split(', ');

var firstArg = args.shift();

var restArgs = args.join(', ');

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

var curriedText =

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

"return function (" + restArgs + ")" + body +

"}";

eval("var curried =" + curriedText);

return curried;
}


[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]

接着是闭包的流行,与数组转换arguments的技术的发现,现代currying函数终于粉墨登场,就好像15~17世纪大航海时代的地理大发现,javascript的世界突然间开阔了许多。
复制代码 代码如下:

//一个简单的现代currying函数
function curry (fn, scope) {
var scope = scope || window;
var args = [];
for (var i=2, len = arguments.length; i < len; ++i) {
args.push(arguments[i]);
};
return function() {
fn.apply(scope, args);
};
}

一般的currying函数只有两重,执行情况如下,第一次执行参数不足返回内部函数,第二次执行才最终完成。不过针对这参数,我们还是可以做一些文章。看如下函数:
复制代码 代码如下:

function sum(){
var result=0;
for(var i=0, n=arguments.length; i<n; i++){
result += arguments[i];
}
return result;
}
alert(sum(1,2,3,4,5)); // 15

这就没有所谓的参数不足问题,传入一个参数,它也计算。但不传入参数呢?无错,区别在于有没有参数。我们可以让它不断执行自身,如果参数存在的情况下。最后在没有参数的情况下,一次过执行。换言之,前面的步骤是用于储存参数。
var sum2= curry(sum);
sum2= sum2(1)(2)(3)(4)(5);
sum2(); // 15
比起一般的currying函数,这有点难度。具体看注解:
复制代码 代码如下:

var curry= function(fn){//原函数的参数为函数
return function(args){//内部函数的参数为数组,由于立即执行,因此直接到第三重去
//args是相对于第三重内部函数可是全局变量
var self= arguments.callee;//把自身保存起来(就是那个数组为参数的第二重函数)
return function(){ //这才是第二次调用的函数
if(arguments.length){//如果还有要添加的参数
[].push.apply(args,arguments);//apply把当前传入的所有参数放进args中
return self(args);
}else{
return fn.apply(this,args);//apply的第二参数为数组
}
}
}([]);
};


[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]

或者每次传入多个参数:

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]

但上面的函数有不足之处,最后怎么也要放个括号,我们想只要参数足够就返回结果,多出的参数忽略。改进如下:
复制代码 代码如下:

function curry(f) {
if (f.length == 0) return f;
function iterate(args) {
if (args.length <= f.length)
return f.apply(null, args);
return function () {
return iterate(args.concat(Array.prototype.slice.call(arguments)));
};
}
return iterate([]);
}


[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
更多精彩内容其他人还在看

BootStrap数据表格实例代码

本文通过实例代码给大家分享了BootStrap数据表格的相关知识,感兴趣的朋友一起看看吧
收藏 0 赞 0 分享

基于vue的短信验证码倒计时demo

这篇文章主要介绍了基于vue的短信验证码倒计时demo,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解React Native开源时间日期选择器组件(react-native-datetime)

本篇文章主要介绍了详解React Native开源时间日期选择器组件(react-native-datetime),具有一定的参考价值,有兴趣的可以了解一下
收藏 0 赞 0 分享

JS库particles.js创建超炫背景粒子插件(附源码下载)

particles.js用于创建粒子的轻量级 JavaScript 库。使用方法非常简单,代码也很容易实现,下面通过本文给大家分享JS库particles.js创建超炫背景粒子插件附源码下载,需要的朋友参考下吧
收藏 0 赞 0 分享

JS库之Waypoints的用法详解

waypoints的功能非常强大,一款用于捕获各种滚动事件的插件,下面跟随脚本之家小编一起学习JS库之Waypoints的用法吧
收藏 0 赞 0 分享

强大的JavaScript响应式图表Chartist.js的使用

本篇文章主要介绍了强大的JavaScript响应式图表Chartist.js的使用,具有一定的参考价值,有兴趣的可以了解一下
收藏 0 赞 0 分享

详解wow.js中各种特效对应的类名

本篇文章主要介绍了wow.js中各种特效对应的类名 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

JS库之Highlight.js的用法详解

highlight.js是一款轻量级的Web代码语法高亮库。下面通过实例代码给大家分享JS库之Highlight.js的用法详解,感兴趣的朋友跟随脚本之家小编一起学习吧
收藏 0 赞 0 分享

详解动画插件wow.js的使用方法

本篇文章主要介绍了动画插件wow.js的使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

JS库 Highlightjs 添加代码行号的实现代码

Highlightjs是一款优秀的代码高亮Js组件,可以很方便地对各种语言编写的代码添加语法高亮样式。本文重点给大家介绍Highlightjs 添加代码行号的实现代码,需要的朋友参考下吧
收藏 0 赞 0 分享
查看更多