Home > Web Front-end > JS Tutorial > body text

Detailed explanation of JavaScript function currying

黄舟
Release: 2017-02-27 14:29:14
Original
1528 people have browsed it

Detailed explanation of JavaScript function currying

Baidu Encyclopedia’s explanation of currying: In computer science, currying (Currying) is to accept A technique that transforms a function with multiple parameters into a function that accepts a single parameter (the first parameter of the original function) and returns a new function that accepts the remaining parameters and returns a result. This technique was named by Christopher Strachey after logician Haskell Curry, although it was invented by Moses Schnfinkel and Gottlob Frege.
I believe that few people can immediately understand what function currying is after reading the above explanation. In layman's terms, the main purpose of function currying is to reduce function parameters and privatize some fixed parameters. The following shows a very simple code for calculating the area of ​​a circle to illustrate the principle of function currying:

//circle函数,接受半径r和πfunction circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    return area;
}/*
 * 通过函数柯里化来简化circle函数,只传入半径就能计算出面积
 * 不管怎么样,π是不会变的,因此我们将他写死,不需要外部调用传入
 */function curryCircle(r){
    var p=3.14;    var area=p*r*r;    return area;
}
Copy after login
Copy after login

Maybe you will think this code is weird, but this is the true face of function currying. Of course, the above code is just a very small example. Function currying in the real world will be a little more vicious. Let's discuss a more general example below. Assuming that π is not unique (for example, we have three kinds of π), π in our formula for calculating the circle area will change according to different scenarios. At this time, we cannot directly write it down, but need to configure π according to different environments:

//circle函数,接受半径r和π
function circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    
    return area;
}
//针对circle函数的柯里化函数function curry(fn,p){
    var finalMethod=function(r){
        var result=fn(r,p);        return result;
    }    return finalMethod;
}
//我们有3种不同的πvar curryCircle1=curry(circle,1.14);
var curryCircle2=curry(circle,2.14);
var curryCircle3=curry(circle,3.14);
//输出:4.56  8.56  12.56
console.log(curryCircle1(2),curryCircle2(2),curryCircle3(2));
Copy after login

As you can see, the curry method encapsulates the most basic circle method, saves the set p parameter (π), and returns a finalMethod method, so that when we finally call finalMethod, we only need to pass in the parameter r (radius) That's it. With the help of function currying, we have three simplified methods for calculating the area of ​​a circle. The function currying shown above can only be applied to the calculation of the circle area. This time we write a more general currying function:

function curry(fn){
    //第一个参数是基础执行方法,slice切除
    var args=Array.prototype.slice.call(arguments,1);    //直接返回匿名函数
    return function(){
        //slice新参数以便能调用concat
        var innerArgs=Array.prototype.slice.call(arguments);        //将配置的参数和新传入的参数合并
        var finalArgs=args.concat(innerArgs);        return fn.apply(null,finalArgs);
    };
}
Copy after login
Copy after login

The main job of the curry() function is to return the parameters of the function Sort. The first parameter of Curry() is the function to be curried, and the other parameters are the values ​​to be passed in. In order to obtain all parameters after the first parameter, the slice() method is called on the arguments object, and parameter 1 is passed in to indicate that the returned array contains all parameters starting from the second parameter. The args array then contains the arguments from the external function. In the inner function, the innerArgs array is created to store all incoming parameters (slice() is used again). Once you have the parameter arrays that store the external and internal functions, you can use the concat() method to merge them into finalArgs. Finally use apply() to pass the result to the function. This achieves a general function currying. If readers who still have energy up to this point can continue reading, we will introduce function currying used in jQuery.
When currying a method, we don’t even need to pass in fn to tell currying to wrap our function. We can directly bind the function to currying through the prototype:

Function.prototype.curry=function(){
    //利用原型的便利,我们可以直接通过this引用到方法
    var fn=this;    var args=Array.prototype.slice.call(arguments);    return function(){
        var arg=0;        //循环校验先前传入的参数和新传入的参数是否有差别
        for(var i=0;i<args.length && arg<arguments.length;i++){            if(args[i]===undefined){
                args[i]=arguments[arg++];
            }
        }        return fn.apply(this,args);
    };
};
Copy after login
Copy after login

Different from before, we obtain the method reference through this reference, so when we need to curry a function, we only need to write like this:

var delay=setTimeout.curry(undefined,10);
Copy after login
Copy after login

delay is one that has been set in advance setTimeout function with 10 millisecond delay. We still use args to save the parameter configuration, but this time there is a difference: the difference between args and arguments will be checked inside the for loop to complete parameter splicing. Therefore, the parameters passed to curry must be complete parameters (which means that undefined values ​​must be passed in). Finally we implemented a currying method that does not require passing in fn.

Detailed explanation of JavaScript function currying

Baidu Encyclopedia’s explanation of currying: In computer science, currying is to transform a function that accepts multiple parameters into one that accepts one A technique that takes a function with a single parameter (the first parameter of the original function) and returns a new function that accepts the remaining parameters and returns a result. This technique was named by Christopher Strachey after logician Haskell Curry, although it was invented by Moses Schnfinkel and Gottlob Frege.
I believe that few people can immediately understand what function currying is after reading the above explanation. In layman's terms, the main purpose of function currying is to reduce function parameters and privatize some fixed parameters. The following shows a very simple code for calculating the area of ​​a circle to illustrate the principle of function currying:

//circle函数,接受半径r和πfunction circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    return area;
}/*
 * 通过函数柯里化来简化circle函数,只传入半径就能计算出面积
 * 不管怎么样,π是不会变的,因此我们将他写死,不需要外部调用传入
 */function curryCircle(r){
    var p=3.14;    var area=p*r*r;    return area;
}
Copy after login
Copy after login

Maybe you will think this code is weird, but this is the true face of function currying. Of course, the above code is just a very small example. Function currying in the real world will be a little more vicious. Let's discuss a more general example below. Assuming that π is not unique (for example, we have three kinds of π), π in our formula for calculating the circle area will change according to different scenarios. At this time, we cannot directly write it down, but need to configure π according to different environments:

//circle函数,接受半径r和πfunction circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    return area;
}//针对circle函数的柯里化函数function curry(fn,p){
    var finalMethod=function(r){
        var result=fn(r,p);        return result;
    }    return finalMethod;
}
//我们有3种不同的π
var curryCircle1=curry(circle,1.14);
var curryCircle2=curry(circle,2.14);
var curryCircle3=curry(circle,3.14);
//输出:4.56  8.56  12.56
console.log(curryCircle1(2),curryCircle2(2),curryCircle3(2));
Copy after login

可以看到,curry方法通过封装最基础的circle方法,同时保存设置好的p参数(π),并返回一个finalMethod方法,这样我们最终调用finalMethod时就只需要传入参数r(半径)就可以完成。借助函数柯里化,我们拥有了三个简化的计算圆面积方法。上面展示的函数柯里化只能适用于圆面积的计算,这次我们编写一个更通用的柯里化函数:

function curry(fn){
    //第一个参数是基础执行方法,slice切除
    var args=Array.prototype.slice.call(arguments,1);    //直接返回匿名函数
    return function(){
        //slice新参数以便能调用concat
        var innerArgs=Array.prototype.slice.call(arguments);        //将配置的参数和新传入的参数合并
        var finalArgs=args.concat(innerArgs);        return fn.apply(null,finalArgs);
    };
}
Copy after login
Copy after login

curry()函数的主要工作就是将被返回函数的参数进行排序。Curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。为了获取第一个参数之后的所有参数,在arguments对象上调用了slice()方法,并传入参数1表示被返回的数组包含从第二个参数开始的所有参数。然后args数组包含了来自外部函数的参数。在内部函数中,创建了innerArgs数组用来存放所有传入的参数(又一次使用了slice())。有了存放来自外部函数和内部函数的参数数组后,就可以使用concat()方法将他们合并成finalArgs。最后使用apply()将结果传递给该函数。这样就实现了一个通用的函数柯里化。如果到这此还有余力的读者可以接着往下看,我们将要介绍jQuery中使用的函数柯里化。
在针对某个方法进行柯里化时,我们甚至不用传入fn来告诉柯里化来包装我们的函数,我们可以通过原型直接将函数和柯里化绑定:

Function.prototype.curry=function(){
    //利用原型的便利,我们可以直接通过this引用到方法
    var fn=this;    var args=Array.prototype.slice.call(arguments);    return function(){
        var arg=0;        //循环校验先前传入的参数和新传入的参数是否有差别
        for(var i=0;i<args.length && arg<arguments.length;i++){            if(args[i]===undefined){
                args[i]=arguments[arg++];
            }
        }        return fn.apply(this,args);
    };
};
Copy after login
Copy after login

与之前不同,我们通过this引用获取了方法引用,这样当我们需要将某个函数柯里化时,只要这样写就可以:

var delay=setTimeout.curry(undefined,10);
Copy after login
Copy after login

delay就是一个已经被提前设定了10毫秒延迟的setTimeout函数。我们仍然通过args来保存参数配置,不过这次有点区别:在for循环内部会校验args和arguments的区别,以此判断来完成参数拼接。所以传给curry的参数必须是完整参数(即意味着不传的值要传入undefined)。最终我们实现了一个不需要传入fn的柯里化方法。

 以上就是详解JavaScript函数柯里化 的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template