concept
** Currification: ** can be understood as a function that accepts some arguments early, delays execution, and does not immediately output the result, but instead returns a function that accepts the rest of the arguments. Because such a property, also known as a partially computed function, is a step-by-step process of receiving parameters.
The concept is a bit abstract and confusing to understand, so let’s use an example of the Add function to illustrate it
function add(a,b){
return a + b
}
add(1.2) / / 3
Copy the code
After modifying the add function above, we will use pseudo code to implement the following
function curryingAdd(){
// Currified implementation
}
add(1) (2) / / 3
Copy the code
Through the implementation of the pseudo-code, we can see that currization is actually changing the two parameters of add, a and B, to pass one parameter a and then return one parameter B and calculate the result of the two passed parameters. It follows that the Currization function is a gradual process of receiving parameters. ** Through the above pseudo-code, we know the implementation process of Currization, next let’s pseudo-code step by step implementation below
The implementation process
// Define a Currization function. Wrap ordinary functions as Currization functions
function currying(fn) {
let args = [];
const inner = function () {
// Start collecting parameters with each call
let _args = [].slice.apply(arguments);
// If there are parameters to continue collecting,
// If there are no arguments, the collected arguments are passed to the function call
if (_args.length > 0) { args.push(... _args);return inner;
} else {
// The args was not released due to closure, resulting in the following calls retaining the arguments passed in last time
// Clear it manually
// There is no need to handle this in real development. In the development process, we collect the arguments and reuse the last argument with each call
const params = [...args]
args = []
return fn.apply(null, params); }};// Return a function
return inner;
}
// Define ordinary functions
function add(){
const args = [].slice.apply(arguments);
return args.reduce((acc,cur) = >{return acc+cur},0)}// wrap the add function as a Cremation function
const curryingAdd = currying(add)
console.log(curryingAdd(1.2.3) ());/ / 6
console.log(curryingAdd(1.2) (3) ());/ / 6
console.log(curryingAdd(1) (2) (3) ());/ / 6
Copy the code
According to the above implementation process, it can be found that the principle of The Currization function is not complicated, just collect the parameters and call it at the appropriate time. However, as a result of the above implementation process, we have to execute an empty parameter at the end of the call. Is there a way to get the result without executing the last step? The answer is yes!!
Based on our knowledge of prototypes and prototype chains, we know that there are two methods on the prototype of a function, toString and valueOf. Things get interesting when js implicitly calls the valueOf and toString methods to get the desired value, depending on the context
function currying(fn) {
let args = [];
const inner = function () {
let _args = [].slice.apply(arguments); args.push(... _args);return inner;
};
inner.toString = function () {
const params = [...args]
args = []
return fn.apply(null, params);
};
inner.valueOf = function () {
const params = [...args]
args = []
return fn.apply(null, params);
};
return inner;
}
Copy the code
This can only be done in a browser, and the node.js environment will still print out the function’s prototype. But the principle is clear.
The effect of cremation
So to figure out how it works, let’s look at what cremation does, why cremation is used. Based on the above implementation, it can be seen that the implementation of Currization is also a closure process, so currization has the advantages of closures.
- Reuse of parameters
- Confirmation in advance
- Delay the
Let’s start with 1 and 3, not to mention parameter reuse, closure properties. Deferred execution, such as the bind mechanism used in JS, is implemented by corrification, which returns a function to be called at the time it is used. Validation in advance, because we return one function at a time, allows us to know at run time that we are going to get an error on that parameter, spreading errors within one function over multiple functions.
Application scenarios
Take a look at an application scenario of Cremation, which is also a problem I encountered in the process of actual development. ** : ** Pass two dates, calculate the difference between the two dates by how many years, how many months, how many days, if no year is passed, return how many months and how many days.
Example:
function diffDate(date1,data2,type){
// TODO
}
diff('2020-04-01'.'2021-05-03'.'year') // 2 days in January 1 year
diff('2020-04-01'.'2021-05-03'.'month') // 2 days in 13 months
diff('2020-04-01'.'2021-05-03'.'day') / / 397 days
Copy the code
Problem solving process:
A moment package is usually used to handle date-related content in front-end projects. Currently, moment is no longer maintained. It is the same with day.js. So in this case, the API that we’re looking for is diff
const moment = require('moment')
const diffDate = (begin, end) = > {
If begin > end returns negative
let flag = false;
const contrast = () = > {
if (moment(begin).isAfter(end)) {
flag = true;
return [end, begin];
}
return [begin, end];
};
// Compare dates with smaller dates in front and larger dates behind
let [from, to] = contrast();
function computed() {
const args = [].slice.apply(arguments);
let diffObj = {};
args.forEach((arg) = > {
// Based on the passed argument. Calculation time difference
const diff = Math.abs(moment(from).diff(moment(to), arg));
// Update from time, update the start time to continue comparison after comparison
from = moment(from).add(diff, arg); diffObj = { ... diffObj, [arg]: diff, }; });return diffObj;
}
const computedDate = currying(computed);
const result = computedDate('Years') ('Months') ('Days') ();console.log(flag, result); // false { Years: 1, Months: 1, Days: 2 }
};
diffDate('2021-04-01'.'2022-05-03');
Copy the code
** Analysis: ** Application scenario is to calculate whether A product has expired, how many days of expiration, how many days of expiration, the expiration date is known. For example, the expiration date of product A is 2022-05-03, and today is 2021-04-01. Start date from 2022-04-01, start date from 2022-04-01, start date from 2022-04-01, start date from 2022-04-01, start date from 2022-04-01. Up to the day.
You can see the first way of using the Currization function.