Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Today in the little Red Book turned to a noun: function corrification.
explain
An official explanation was found:
Currying, English: Currying, is a technique that converts a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returns a new function that takes the remaining arguments and returns a result.
The basic approach to function curryification is the same as function binding: use a closure to return a function. The difference is that when a function is called, the returned function also needs to set some of the parameters passed in.
A currie function is typically created dynamically by calling another function and passing it the function to be currie and the necessary arguments.Copy the code
// The normal add function
function add(x, y) {
return x + y
}
/ / after Currying
function curryingAdd(x) {
return function (y) {
return x + y
}
}
add(1.2) / / 3
curryingAdd(1) (2) / / 3
Copy the code
Instead of taking the x and y arguments to add, you have a function that takes x and then returns a function that handles the y argument. You call the function by passing it only one of the arguments and then having it return a function that handles the rest.
It takes a long time. Why do you do that?
The benefits of currization
Parameters of reuse
Normal re validation string
// The function is wrapped
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g.'test') //false
check(/[a-z]+/g.'test') //true
/ / after Currying
Copy the code
Currization validation
function curryingCheck(reg) {
return function(txt) {
return reg.test(txt)
}
}
const hasNumber = curryingCheck(/\d+/g);
const hasLetter = curryingCheck(/[a-z]+/g);
hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false
Copy the code
Normally, you can just call the check function, but if you need to check for numbers in many places, you actually need to reuse the first parameter reg, so that you can call hasNumber, hasLetter, etc., so that the arguments can be reused, so that it is easier to call.
(Other benefits, I haven’t figured out so far o(╥﹏╥)o)
Currize the general packaging method
// Initial encapsulation
var currying = function(fn) {
// args gets all the arguments in the first method
var args = Array.prototype.slice.call(arguments.1)
return function() {
// merge all the parameters in the following method with args
var newArgs = args.concat(Array.prototype.slice.call(arguments))
// apply the merged parameters as fn parameters and execute them
return fn.apply(this, newArgs)
}
}
Copy the code
The first is a preliminary wrapper, storing the initial arguments in a closure, then concatenating them by taking the remaining arguments, and finally executing functions that require currying.
If there are multiple parameters, we need to add recursion and encapsulate another layer:
// Support multiple parameter passing
function progressCurrying(fn, args) {
var _this = this
var len = fn.length;
var args = args || [];
return function() {
var _args = Array.prototype.slice.call(arguments);
Array.prototype.push.apply(args, _args);
// If the number of arguments is less than the original fn.length, the recursive call continues to collect arguments
if (_args.length < len) {
return progressCurrying.call(_this, fn, _args);
}
// After parameters are collected, run fn
return fn.apply(this, _args); }}Copy the code
The performance of the curry
-
Accessing arguments objects is usually slower than accessing named arguments;
-
Some older browsers are quite slow to implement arguments.length;
-
Use fn.apply(…) And fn. Call (…). It’s usually better than calling fn(…) directly. A little slower;
-
Creating lots of nested scopes and closures costs money, both in memory and speed;
The interview questions
Implement an add method that satisfies the following expectations: add(1) (2) (3) = 6;
add(1.2.3) (4) = 10;
add(1) (2) (3) (4) (5) = 15;
Copy the code
Reference answer:
function add() {
// On the first execution, an array is defined to store all the parameters
let _args = Array.prototype.slice.call(arguments);
// Internally declare a function that uses closure properties to hold _args and collect all parameter values
let sumNum = function() { _args.push(... arguments);return sumNum;
};
// Take advantage of the toString implicit conversion feature to implicitly convert when finally executed and calculate the final value returned
sumNum.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return sumNum;
}
Copy the code