What is curried
Currying is also a common concept, as wikipedia explains:
In computer science, currying, also translated as carrey or callization, is a technique of converting a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returning a new function that takes the remaining arguments and returns a result. This technique was named after logician Haskell Gary by Christopher Strachey.
More succinctly: Currization is the technique of transforming a function that takes multiple arguments into a function that takes a single argument and returns a new function that takes the remaining arguments and returns the result.
Still don’t understand, it doesn’t matter, the following through a few examples step by step to understand the Corrification.
How do you curry it
Implement a function to filter an array, filtering out items less than 10. The traditional approach is:
const filterLowerThan10 = (array) = > {
let result = [];
for (let i = 0; i < array.length; i++) {
let currentValue = array[i];
if (currentValue < 10) { result.push(currentValue); }}return result;
};
Copy the code
It’s easy to implement, but the current filter is for items less than 10. If this threshold changes, we can use curried ideas to change it:
const filterLowerNumber = (number) = > {
return (array) = > {
let result = [];
for (let i = 0; i < array.length; i++) {
let currentValue = array[i];
if(currentValue < number) { result.push(currentValue); }}return result;
};
};
const filterLowerThan10 = filterLowerNumber(10);
filterLowerThan10([1.11.8.21.2]); / /,8,2 [1]
// It can also be shortened like this
// filterLowerNumber(10)([1, 11, 8, 21, 2]);
Copy the code
Another scenario implements a common function for finding the sum of two numbers:
function add(x, y) {
return x + y;
}
add(1.2); / / 3
Copy the code
Curried functions:
var add = function (x) {
return (y) = > x + y;
};
add(1) (2); / / 3
Copy the code
On this basis, submit a more complex request to implement the add method as required:
add(1)(2); // result = 3 add(1)(3)(5); // result is 9 add(1)... (n); // The result is sumCopy the code
This may look familiar to you, as it’s the basis for many curry-like interview questions.
Problem solving:
- According to the calling method, each time the add function is executed, it must return a function for subsequent calls, and the returned function still returns itself for multi-level calls.
- When the last call is finished, it returns a function, which needs to be overridden internally (toString).
- To sum, we need to maintain a closure variable args inside the add function. Args is an array that holds the arguments passed in the first call to add and subsequent calls to fn.
- When fn’s toString method is called, it means that the last call is over and the function is returned, so we can calculate the sum of all values in the args array to get the result.
const add = (arg1) = > {
let args = [arg1];
const fn = (arg2) = > {
args.push(arg2);
return fn;
};
// The toString method of fn will be returned after the last execution, which is equivalent to calling fn toString method
fn.toString = function () {
return args.reduce((prev, item) = > prev + item, 0);
};
return fn;
};
add(1) (2) (3); / / 6
Copy the code
Here, only a single parameter can be passed in each call. To support multiple parameters can be passed in each call, change to:
const add = (. arg1) = > {
let args = [...arg1];
const fn = (. arg2) = > {
args = [...args, ...arg2];
return fn;
};
fn.toString = function () {
return args.reduce((prev, item) = > prev + item, 0);
};
return fn;
};
add(1) (2.3.4) (5); / / 17
Copy the code
We can calculate the result correctly, but if we use === to make a judgment between the expression and the result
add(1) (2) (3) = = =6; //false
add(1) (2.3.4) (5) = = =15; //false
Copy the code
The output is always false, which is not surprising. As mentioned in the above code, add always returns Function. This is achieved by modifying fn’s toString method, but it does not change the type of the returned value. Function again.
The curry is changed
The point of anti-currying is to extend the applicability of functions, so that functions that are owned by specific objects can be used by any object.
function Person() {
this.message = "wowowo";
}
Person.prototype = {
speak: function () {
console.log(this.message); }};Copy the code
Person instances can all use the speak method:
new Person().speak();
Copy the code
If there is a variable object:
const dog = {
message: "wang wang wang!"};Copy the code
This object also wants to use the Speak method on the Person prototype, and needs to be anti-curried:
const unCurrySpeak = unCurry(Person.prototype.speak);
unCurrySpeak(dog);
Copy the code
UnCurry is the anti-currying method we’re going to implement. UnCurry returns a new function whose first argument is the object (dog) that is expected to execute the method, followed by arguments that need to be passed when the method is executed.
function unCurry(fn) {
return function () {
var obj = [].shift.call(arguments);
return fn.apply(obj, arguments);
};
}
Copy the code
You can do this, or you can mount Uncurry on a function prototype.