javascript的currying函数介绍

最早期的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;
}

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;
}
function sum(x, y) {
return x + y;
}
function mean3(a, b, c) {
return (a + b + c)/3;
}
var a = curry(sum)(10)(15)
alert(a)//25
var b = curry(mean3)(10)(20, 30);
alert(b)//20
var c = curry(curry(sum))(10)()(20);
alert(c);
var d = curry(curry(mean3)(10))(20)(30);
alert(d);

[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的第二参数为数组
}
}
}([]);
};

代码如下:

function sum(){
var result=0;
for(var i=0, n=arguments.length; i<n; i++){
result += 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; i<n; i++){
result += 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([]);
}

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([]);
}
function mean3(a, b, c) { return (a + b + c) / 3; }
var curriedMean3 = 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 (第四个参数无效)

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]

(0)

相关推荐

  • javascript currying返回函数的函数

    最早期的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

  • javascript的currying函数介绍

    最早期的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

  • 深入剖析JavaScript中的函数currying柯里化

    curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名).   柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个简单的例子 var concat3Words = function (a, b, c) { r

  • JavaScript 中定义函数用 var foo = function () {} 和 function foo()区别介绍

    某天写代码突然县道这个问题,顺势总结一波 JavaScript 函数和变量声明的"提前"(hoist)行为 简单的说 如果我们使用 匿名函数 var a = {} 这种方式, 编译后变量声明a 会"被提前"了,但是他的赋值(也就是a)并不会被提前. 也就是,匿名函数只有在被调用时才被初始化. 如果使用 function a () {}; 这种方式, 编译后函数声明和他的赋值都会被提前. 也就是说函数声明过程在整个程序执行之前的预处理就完成了,所以只要处于同一个作用域

  • javascript条件式访问属性和箭头函数介绍

    目录 一.条件式访问属性 二.箭头函数介绍 一.条件式访问属性 ?. 是ES2020引入的新特性,是一个条件式属性访问操作符,当你访问值为undefined变量的某个属性值时,如果使用.操作符会直接报错,如果使用条件式属性访问操作符来访问会返回undefined. 看例子: let book = {price:10, edition:10, name:"javascirpt" } console.log(book.page.num) 直接报错: TypeError: Cannot re

  • JavaScript的function函数详细介绍

    通过函数来封装任意多条语句,而且可以在任何地方.任何时间调用执行. 而我们的JavaScript脚本语言比较特殊,相对于C语言,它的参数是不需要数据类型加持的.返回值return,我就不过多描述,他是和 C语言通的,如果没写他就会自动返回undefined function fun(x,y){ } //写成这样就可以声明一个函数 以我的理解他就是以对象的形式来传入参数,通过对象的各项属性值(引用类型的值),来作为我的实际参数, 例如我有以下做法: function fun(x, y) { //

  • JavaScript数组去重和扁平化函数介绍

    目录 1.数组扁平化(又称数组降维) 方法一:使用 reduce 方法 方法二:栈 2.数组去重 方式一:Set(ES6) 方式二:reduce 方法三:filter 1.数组扁平化(又称数组降维) flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回 const test = ["a", ["b", "c"], ["d", ["e", ["

  • javascript中普通函数的使用介绍

    复制代码 代码如下: <html> <head> <title>javascript中普通函数的使用</title> <script> function show(){ document.write("show函数被调用" + "<br/>"); return 10; } var hello = show();//show()函数被调用,将返回值赋值给hello变量.如果函数没有返回值,则返回u

  • 深入浅析javascript立即执行函数

    javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花; 当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解.  JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function: function functionname() { 这里是要执行的代码 } 当调用该函数时,会执行函数内的代码. 可以在某事件发生时直接调用函数(比如当用户点击按钮时),并且可由 JavaScript

  • JavaScript常用验证函数实例汇总

    本文实例汇总了JavaScript常用验证函数.分享给大家供大家参考.具体汇总如下: 一.字符串类验证 1. 长度限制 复制代码 代码如下: <script> function test() { if(document.a.b.value.length>50) { alert("不能超过50个字符!"); document.a.b.focus(); return false; } } </script> <form name=a onsubmit=&

  • JavaScript中eval()函数用法详解

    eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行. 如果参数是一个表达式,eval() 函数将执行表达式.如果参数是Javascript语句,eval()将执行 Javascript 语句. 语法 复制代码 代码如下: eval(string) 参数 描述 string 必需.要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句. eval()函数用法详解: 此函数可能使用的频率并不是太高,但是在某些情况下具有很大的作用,下面就介绍一下eva

随机推荐