In-depth understanding of JavaScript function Advanced series The second chapter--function currying

Source: Internet
Author: User

Previous words

The concept of function currying currying was first invented by Russian mathematician Moses Schönfinkel, and then by the famous mathematical logic biologist Haskell curry its enrichment and development, currying from this name. This article will detail the function of the curry (curring)

Defined

Currying is also called partial evaluation. A currying function will first accept some parameters, after accepting these parameters, the function will not be evaluated immediately, but continue to return another function, just passed the parameter in the function formed in the closure of the save. Until the function is really needed to evaluate, all parameters passed in before are evaluated once.

The literal understanding of currying is not easy, and the following is an explanation of the function currying by writing a function that calculates the monthly cost currying

Monthly cost function

Before the end of each day, keep a record of how much money is spent today. The code is as follows:

varMonthlycost =0;varCost =function (Money) {Monthlycost+=Money ;}; Cost ( -);//1th Day OverheadCost $);//2nd day OverheadCost -);//3rd day Overhead//...Cost the);//30th Day Overheadalert (monthlycost);//Total cost of output 1 months

At the end of the day, the money spent is recorded and calculated to date. But you don't really care how much you spend each day, and just want to know how much it will cost by the end of the month. That is, in fact, it only needs to be calculated at the end

If in the first 29 days of each month, just save the cost of the day, until the last day to evaluate the evaluation, so as to meet our requirements, the code is as follows

  varCost =(function () {varargs = []; returnfunction () {//if there are no arguments, the and in the args array is computed      if(Arguments.length = = =0) {        varMoney =0;  for(vari =0, L = args.length; I < L; i++) { money+=Args[i]; }        returnMoney ; //If there are arguments, only the data can be passed to the args array}Else{[].push.apply (args, arguments);  }    }  })(); Cost ( -);//not really evaluatedCost $);//not really evaluatedCost -);//not really evaluatedConsole.log (Cost ());//Evaluation and output:

General functions

The following is a generic curry function currying,currying accepts a parameter, which is the function that will be currying. If combined with the example above, the function is to traverse the cost of the day of the month and find out the sum of them.

  varcurrying =function (FN) {varargs = []; returnfunction () {if(Arguments.length = = =0) {        returnFn.apply ( This, args); } Else{[].push.apply (args, arguments); returnArguments.callee;  }    }  }; varCost =(function () {varMoney =0; returnfunction () { for(vari =0, L = arguments.length; I < L; i++) { money+=Arguments[i]; }      returnMoney ;  }  })(); varCost = currying (cost);//Convert to currying functionCost -);//not really evaluatedCost $);//not really evaluatedCost -);//not really evaluatedAlert (Cost ());//Evaluation and output:

This completes the writing of a currying function. When cost () is called, if some parameters are explicitly in place, indicating that no real evaluation is performed at this time, but rather that these parameters are saved, the cost function returns another function. Only when cost () is executed in the form of an argument, the evaluation is really started using all the previously saved parameters.

The function of the parameter can be passed

In fact, the curry function can not only receive the function to be curry as a parameter, but also can receive some necessary parameters, the following is the improved code of function Curry (currying)

  varcurrying =function (FN) {varargs = []; //stores parameters other than FN in the curring function and stores them in the args functionargs = Args.concat ([].slice.call (arguments,1)); returnfunction () {if(Arguments.length = = =0) {        returnFn.apply ( This, args); } Else {        //expands the parameters in FN and then stores them in the args array[].push.apply (args, arguments);  }    }  }; varCost =(function () {varMoney =0; returnfunction () { for(vari =0, L = arguments.length; I < L; i++) { money+=Arguments[i]; }      returnMoney ;  }  })(); varCost = currying (Cost, -, $);//Convert to currying functionCost -, $);//not really evaluatedCost -);//not really evaluatedConsole.log (Cost ()));//Evaluation and output:

Evaluation currying

If the function is curring, and the argument is accompanied by a process of evaluation, the code is simplified as follows

  varcurrying =function (FN) {//to get parameters other than FN    varargs = [].slice.call (arguments,1); returnfunction () {//get all parameters in the FN      varInnerargs =[].slice.call (arguments); //The final parameter list is the combination of args and Innerargs      varFinalargs =Args.concat (Innerargs); //Expand the parameters in the Finalargs and upload them to FN to execute      returnFn.apply (NULL, Finalargs);  };  }; varCost =(function () {varMoney =0; returnfunction () { for(vari =0, L = arguments.length; I < L; i++) { money+=Arguments[i]; }      returnMoney ;  }  })(); varCost = currying (Cost, -, $);//Convert to currying functionCost -);//100+200+300=600Cost -, -);//(100+200+300) + (100+200+100+100) =1100

Anti-currying

The method on Array.prototype can only be used to manipulate the array object. However, using call and apply can pass an arbitrary object as this to a method, so that the method used in this place is no longer confined to the original set of objects, but to be generalized and get wider applicability

Is there a way to extract the process of generalizing this? Anti-Curry (uncurrying) is used to solve this problem. Anti-curry is mainly used to enlarge the scope of application and to create a function that is wider in scope. Extend to more objects a method that would otherwise apply only to a particular object.

Uncurrying's topic comes from an article published by Brendan Eich, the father of JavaScript, in 2011. The following code is one of the ways that Uncurrying is implemented:

Function.prototype.uncurrying = function () {   varthis;   return function () {    var obj = Array.prototype.shift.call (arguments);     return _this.apply (obj, arguments);  };};

Another way to implement this is

Function.prototype.currying = function () {    varthis;     return function () {        return  Function.prototype.call.apply (_this, arguments);}    }

In the end, they all convert This.method into method (This,arg1,arg2 ...) To implement method borrowing and generalization of this

Here's an example of a common object having a push method

var push = Array.prototype.push.uncurrying (),    = {};   '  First ' '  Both ' );  Console.log (obj); /* obj {    0: "First",    1: "Both"}* /

By way of Uncurrying, Array.prototype.push.call becomes a general push function. As a result, the push function acts like Array.prototype.push, and is not limited to manipulating only the array object. For the user, the way to invoke the push function is more concise and clear.

Finally, let's look at an example

vartoUpperCase =String.prototype.toUpperCase.uncurrying (); Console.log (toUpperCase ('AVD'));//AVDfunction Aryupper (ary) {returnAry.map (touppercase);} Console.log (Aryupper (['a','b','C']));//["A", "B", "C"]

In-depth understanding of JavaScript function Advanced series The second chapter--function currying

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.