The Cremation principle

Convert a multi-parameter function to a single-parameter function

Input and output

The input

A function

The output

There are two cases:

  1. The input function returns a function if its arguments are not evenly distributed.
  2. Returns the execution result of the input function when the parameters of the input function are passed uniformly.

Pay attention to the point

The length property of the function

Returns the length of a function argument

function a(a,b,c){
	return a+b+c;
};
a.length; / / 3
Copy the code

implementation

1. Another way to call ordinary functions

Changed the way of parameter passing (call fn function directly when all parameters are passed, and give the parameter of return function to FN)

Curry (fn)(fn)(… Args), in which args is passed to the fn function.

function curry(fn){
	if(fn.length <=1) {return fn}
	var returnFn = (. args) = > {
		if(fn.length === args.length){
			// Call the fn function directly and pass the parameters of the return function to fn
			returnfn(... args) }else{
			// Print the parameters passed in if the parameters are not complete.
			console.log(args)
			
		}
	}
	return returnFn
}
var add = (a,b,c,d) = > a+b+c+d;
var curriedAdd = curry(add);
curriedAdd(1.2.3); // Print [1, 2, 3]
Copy the code

Analysis of the

  • Curry returns a function.
  • Pass arguments to the returned function
  • When the number of arguments of returnFn is the same as the number of arguments of the input function fn
  • Call the fn function and pass the returnFn argument to the fn.
  • Returns the result of the previous call. This is equivalent to calling the input function in a different way.
Add call method comparison:

Normal function calls:

var add = (a,b,c,d) = > a+b+c+d;
add(1.2.3.4)
Copy the code

Curry wrapped invocation

var add = (a,b,c,d) = > a+b+c+d;
var returnFn = curry(add);
returnFn(1.2.3.4)

Copy the code
  1. Don’t call Add directly. Instead, you pass Add as an argument to another function, Curry.
  2. Returns a function, returnFn.
  3. Pass arguments to the returning function.
  4. Returns the called fn inside the returned function.
  5. The overall equivalent of curry(add)(1,2,3,4), curry’s first argument is the function we want to call. The argument that returns the function is the argument that we want to call the function.

2. Full Version of Corrification (es6 version) (recursion + parameter concatenation)

Parameter stitching is flexible. This approach is recommended

function curry(fn){
	if(fn.length <=1) {return fn}
	var returnFn = (. args) = > {
		//console.log(... args,typeof ... args);
		if(fn.length === args.length){
			// When all parameters are passed
			returnfn(... args) }else{
			// Return a function if the parameters are not complete
			return (. args2) = > {
				console.log(args2,"",args);
				returnreturnFn(... args,... args2) } } }return returnFn
}
var add = (a,b,c,d) = > a+b+c+d;
/ / add packing
var returnFn = curry(add);
// Recursively pass arguments to the returnFn
var returnFnArrowFn = returnFn(1) (2) (3);
ReturnFn passes the arguments to the input function fn and calls fn
returnFnArrowFn(4);/ / 10
Copy the code

Parameter passing when recursively calling returnFn

The printout of console.log(args,args2) in the code above

console.log(args,args2);
/ / [1] [2]
/ / [1, 2] [3]
// [1,2,3]    [4]
// When the parameters are complete, go to the if branch above. Call the input function fn.
Copy the code

Args is the argument to returnFn. Args2 is the argument to the anonymous function in returnFn.

Analysis of the

  1. If the number of parameters is <=1, the input function is returned
  2. Defines the returned function, and returns
  3. If the number of input parameters is equal to the number of parameters of the input function fn, then it indicates that all parameters are complete. Directly call the input function fn and pass the parameters of the return function to the input function. (Because our final goal is to call the input function, and of course the arguments are for fn)
  4. Always return a function.
  5. The arguments to the returned function are passed to the returnFn function.
  6. Recursively calls the returnFn function
  7. Until the arguments are passed from the innermost return function to the returnFn function. The arguments to the returnFn function are passed to the input function.
  8. Note: The input function is passed only if the number of arguments in the return function is the same as the number of arguments in the input function. And calls the input function and returns.

Drawing analysis

3. Implementation method three (ES5 version) (recursion + parameter splicing)

In THE ES5 version, parameter stitching is cumbersome.

function curry(fn, args=[]) {// The args parameter is not recommended
    length = fn.length;
   // args = args || [];

    return function() {
        // Copy the second argument array in Curry to _args
        var _args = args.slice(0),
        arg, i;
        for (i = 0; i < arguments.length; i++) {
            arg = arguments[i];
            // Push the return function argument to _args.
            // _args is used to store all the continuously passed arguments.
            _args.push(arg);
        }
        if (_args.length < length) {
            // When arguments are inconsistent, recursively calls itself and passes the existing concatenated arguments to Curry.
            // Call the input function fn and pass in all the concatenated arguments.
            return curry.call(null, fn, _args);
        }
        else {
            // The last step of the curry function, with all the arguments passed, begins the call to fn.
            return fn.apply(null, _args);// This in an anonymous function. I'm pointing to window. There is no need to modify this.}}}var returnFn = curry(function(a, b, c) {
    return a+b+c;
});

var nextFn = returnFn(1) (2);// Return an anonymous function to collect parameters
nextFn(3); // 6 // When the parameters are complete, call curry's fn to evaluate.
Copy the code

Analysis of the

  • Use the second argument of curry’s function to collect successive incoming arguments.
  • Concatenate the parameter with the newly passed parameter using the _args variable
  • Call Curry recursively, passing in the concatenated arguments.
  • Until, _args.length === length, the total number of arguments passed is the same as the number of arguments in the curry-wrapped function fn
  • Call fn and pass in all the connected arguments.
  • Returns the result of the fn execution.

reference

  • Juejin. Cn/post / 684490…

Application scenarios

  • ajax
  • Code to simplify
  • Ramdajs, Underscorejs, LoDash and other libraries use the functional idea
  • Pipe, compose, cond, R.ifelse, etc

Currified scenarios for Ajax

This use of Curry can be understood as parameter reuse. In essence, it is to reduce generality and improve applicability

// Just a hint
function ajax(type, url, data) {
    var xhr = new XMLHttpRequest();
    xhr.open(type, url, true);
    xhr.send(data);
}

// Although ajax is a very generic function, it has redundant arguments when called repeatedly
ajax('POST'.'www.andy.com'."name=andy")
ajax('POST'.'www.andy.com'."name=andy")
ajax('POST'.'www.andy.com'."name=andy")

/ / use of curry
var ajaxCurry = curry(ajax);

// Request data as POST
var post = ajaxCurry('POST');
post('www.andy.com'."name=andy");

// Request data from www.andy.com as POST
var postFromTest = post('www.andy.com');
postFromTest("name=andy");

Copy the code

Currization of the value of an object

longhand

var person = [{name: 'andy'}, {name: 'amy'}];
Copy the code

So let’s take the name from person, what’s the code for that?

var nameArr = person.map((item,index) = > {
    return item.name
});
console.log(nameArr); // ["andy", "amy"]
Copy the code

How do we write it with Ramdajs?

var person = [{name: ‘andy’}, {name: ‘amy’}];

R.map(R.prop('name'))(person); // ["andy", "amy"]
Copy the code

How do I get it through Lodash?

var person = [{name: 'andy'}, {name: 'amy'}];
_.map(person,'name'); // ["andy", "amy"]
Copy the code

How do I get my underscore?

var person = [{name: 'andy'}, {name: 'amy'}];
_.map(person,(item)=>item.name); // ["andy", "amy"]Or: _. The map (person,'name']); // ["andy", "amy"]
Copy the code

The above codes ramdaJS and Lodash, underscore. The difference is that the transmission of data is not the same. Ramdajs is data passing behind. The latter two are before data transmission.

Summary of coriolization applications

  1. The first example above is parameter reuse
  2. The second example is to take a property in an array object and abbreviate three lines of code into one
  3. R.map(R.prop(‘name’))(person); Code readability has been improved. Person object (map) traverses, takes property (prop) ‘name’

Read code as if it were an English sentence.

conclusion

Using functional libraries for several years, the important ideas inside the formation of the article. Review, also hope to read the article of the same students useful. Go deep together.

  1. Corrification, to put it bluntly, is to wrap an ordinary function and call it in another way
  2. When ordinary functions are curried, they become more flexible. It is more reusable
  3. One advantage of Currie: parameter reuse
  4. There are other features of functional expressions: higher-order functions, pure functions (idempotent functions), which we will cover later.
  5. Improve code testability, readability, and code robustness.

The key to curry’s implementation is the return function + recursion + passing of arguments + actually calling the input function