热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javascript的currying函数介绍_javascript技巧

curring的概念将函数式编程的概念和默认参数以及可变参数结合在一起.一个带n个参数,curried的函数固化第一个参数为固定参数,并返回另一个带n-1个参数的函数对象,分别类似于LISP的原始函数car和cdr的行为。currying能泛化为偏函数应用(partialfunctionapplication,PFA),p这种函数将任意数量(顺序)的参数的函数转化为另一个带剩余参数的函数对象
最早期的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 args.push(arguments[i]);
};
return function() {
fn.apply(scope, args);
};
}


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

代码如下:


function sum(){
var result=0;
for(var i=0, n=arguments.length; iresult += 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的第二参数为数组
}
}
}([]);
};


代码如下:


function sum(){
var result=0;
for(var i=0, n=arguments.length; iresult += arguments[i];
}
return result;
};
var curry = function(fn){//原函数的参数为函数
return function(args){//内部函数的参数为数组,由于立即执行,因此直接到第三重去
var self= arguments.callee;//把自身保存起来
return function(){ //这才是第二次调用的函数
if(arguments.length){//如果还有要添加的参数
[].push.apply(args,arguments);
return self(args);
}
else return fn.apply(this,args);//执行
}
}([]);
};
var sum2= curry(sum);
sum2= sum2(1)(2)(3)(4)(5);
alert(sum2());


或者每次传入多个参数:

代码如下:


function sum(){
var result=0;
for(var i=0, n=arguments.length; iresult += arguments[i];
}
return result;
};
var curry = function(fn){//原函数的参数为函数
return function(args){//内部函数的参数为数组,由于立即执行,因此直接到第三重去
var self= arguments.callee;//把自身保存起来
return function(){ //这才是第二次调用的函数
if(arguments.length){//如果还有要添加的参数
[].push.apply(args,arguments);
return self(args);
}
else return fn.apply(this,args);//执行
}
}([]);
};
var sum2= curry(sum);
sum2= sum2(1,2,3);
sum2= sum2(4,5,6);
sum2= sum2(7,8,9);
alert(sum2());


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

代码如下:


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需刷新才能执行]

推荐阅读
  • 前言对于从事技术的人员来说ajax是这好东西,都会使用,而且乐于使用。但对于新手,开发一个ajax实例,还有是难度的,必竟对于他们这是新东西。leo开发一个简单的ajax实例,用的是 ... [详细]
  • 表单提交前的最后验证:通常在表单提交前,我们必须确认用户是否都把必须填选的做了,如果没有,就不能被提交到服务器,这里我们用到表单的formname.submit()看演示,其实这个对于我们修炼道 ... [详细]
  • Itwasworkingcorrectly,butyesterdayitstartedgiving401.IhavetriedwithGooglecontactsAPI ... [详细]
  • Iwouldliketobeabletohaveasidebarthatcanbetoggledinandoutonabuttonpress.However ... [详细]
  • 但有时候,需要当某事件触发时,我们先做一些操作,然后再跳转,这时,就要用JAVASCRIPT来实现这一跳转功能。下面是具体的做法:一:跳转到新页面,并且是在新窗口中打开时:复制代码代码如下:fu ... [详细]
  • JavaScript在常人看来都是门出不了厅堂的小语言,仅管它没有明星语言的闪耀,但至少网页的闪耀还是需要它的,同时它是一门很实用的语言,本人平时就喜欢拿它来写点实用工具或应用,本文演示用JavaSc ... [详细]
  • JavaScript概述1.JavaScript定义JavaScript是Netscape公司开发的一种基于对象和事件驱动的脚本语言。它是弱类型语言,只能由浏览器解释执行。其中:脚本语言:解释运行( ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • JavaScript - let和var区别
    前提ES5只有函数作用域和全局作用域,var属于ES5。let属于ES6,新增块级作用域。目的是可以写更安全的代码。Theletstatementdeclaresablocks ... [详细]
  • 用JavaScript实现的太空人手表
    用JavaScript实现的太空人手表-JS写的太空人手表,没有用canvas、svg。主要用几个大的函数来动态显示时间、天气这些。天气的获取用到了AJAX请求。代码中有详细的注释 ... [详细]
  • javascript如何判断值是否为undefined
    这篇文章主要介绍“javascript如何判断值是否为undefined”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ja ... [详细]
  • Whyusingstringsaskeysofarray,consoleisshowingthatarraywithoutthesedeclaredvaluesand ... [详细]
author-avatar
张洪幸_246
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有