Make writing a habit together! This is the sixth day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

preface

Before we get to the idea of Currization, combinatorial functions, and inertia, let’s look at higher-order functions. Higher-order functions are called higher-order functions. So what is a higher-order function?

Let’s start with some code:

function add(x, y, f) {
    return f(x) + f(y);
}
Copy the code

When we call add(-5, 6, math.abs), the arguments x, y, and f receive -5, 6, and the function math.abs, respectively. According to the function definition, we can derive the calculation as follows:

x = -5;
y = 6;
f = Math.abs;
f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11;
return 11;
Copy the code

JavaScript functions actually refer to a variable. Since variables can point to functions and arguments to functions can accept variables, a function can accept arguments to another function, which is called a higher-order function.

Currie,

What is corrification? What is a Currification? Maybe 100 people have 100 interpretations of it.

  • ✅ Baidu Bai: In computer science, 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.
  • ✅ : Currying is the process of turning a function that originally takes two arguments into a function that takes one. The new function returns a function that takes the original second argument.
  • ✅ Zhihu 1: Currying is a continuous definition of converting a multivariate function into multiple unary functions.
  • ✅ Zhihu 2: Currying, also known as Partial Evaluation, is simply a way of calling a function by passing it some parameters and having it return a function that processes the rest of the parameters.

However, as FAR as I can see, Currying is a programming idea that executes a function that produces a closure that stores some information in advance for use by lower-level contexts. This idea of pre-storing and processing is called the idea of Currified programming.

Creevey is also a frequent interview question, and one of the classic questions is summation.

add(1)(2)(3)(4)(5)(6); // => 21 add(1, 2)(3, 4)(5, 6); // => 21 add(1, 2, 3, 4, 5, 6); / / = > 21Copy the code

This is a more classic interview question, including my own interview also encountered this interview question. At first glance this looks like a Cremation, but it’s actually a little more complicated than cremation, and cremation alone can’t make this call.

The reason for this is that normal Currization can’t just keep on calling for infinitely more arguments, and currization has an end, which obviously doesn’t have an end in this case.

The number of arguments for each call is not known, nor is the number of calls. So it must not return a number each time, only a function. So there’s another question here, if they’re all returned functions, what happens when they need to end? There’s a little bit of detail here.

Knowledge: When an object (including arrays, objects, functions, etc.) participates in a primitive operation such as arithmetic or logic operation, it will call its toString or valueOf method with no arguments to get a primitive value, and then participate in the operation with this primitive value. This should be borrowed from Java, but the rules seem to be more complicated than Java. I didn’t go too far into the details, because JavaScrip t rarely uses this feature (so many people don’t know about it). It’s going to keep calling, it’s going to return a function, it’s going to be a number only because it implements a toString or a valueOf method.

Based on the above, the implementation idea is as follows (certainly not the only one) :

var curring = () => { var result = []; var add = (... args) => { result = result.concat(args); return add; }; add.valueOf = add.toString = () => { return result.reduce((pre, cur) => pre + cur, 0); } return add; }; var add = curring(); console.log(+add(1)(2)(3)(4)(5)(6)); add = curring(); console.log(+add(1, 2)(3, 4)(5, 6)); add = curring(); console.log(+add(1, 2, 3, 4, 5, 6));Copy the code

Combination function

Here is a brief outline of functional and imperative programming.

Functional programming: put specific steps into a function, later when needed, directly call the function, do not care about how the function is implemented. Functional programming is about results. The pros and cons of functional programming are obvious:

  • Advantages: low coupling, high cohesion, convenient development, easy maintenance.
  • Disadvantages: Not flexible enough to do special processing on steps.

Imperative programming: Unlike functional programming, imperative programming focuses on the steps and requires us to implement each step ourselves.

  • Advantages: flexible, can handle each step.
  • Disadvantages: Code redundancy, not efficient enough.

Based on the advantages and disadvantages of functional programming and imperative programming, we advocate the use of functional programming in daily use.

One of the most important concepts in functional programming is function composition, which is essentially the process of piping together function data, and then piping the data through the pipeline to get the final result. Such as:

var a = (x) => x + 1; var b = (x) => x * 2; var c = (x) => x - 1; var res = c(b(a(a(1)))); console.log(res); / / = > 5Copy the code

But this is not very readable, so we can build a composite function that takes any function as an argument, each function can only take one argument, and finally the composite function returns a function. Such as:

var resFn = compose(c, b, a, a);
resFn(1); // => c(b(a(a(1)))) => 5
Copy the code

Compose (c, b, a, a)(x) c(b(a(1))))) But notice that if none of the functions are passed in, it returns what is passed in, and the order in which the functions are executed is the reverse of the order in which they were passed in. These two points need to be noted.

The implementation is as follows:

var compose = (... Funcs) => {// funcs(array) : Return (x) => {var len = funcs.length; var len = funcs.length; var len = funcs.length; var len = funcs.length; If (len === 0) return x; if (len === 1) funcs(x); return funcs.reduceRight((res, func) => { return func(res); }, x); }; }; var resFn = compose(c, b, a, a); resFn(1);Copy the code

The idea of combinatorial functions, used in many frameworks such as Redux, is actually equivalent to the code above.

export default function compose(... funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (... args) => a(b(... args))) }Copy the code

Inert thinking

Lazy function, literally means lazy function, but “wisdom runs deep”, lazy function is not really lazy, on the contrary, it is smart function, why say it is smart, because it does not repeat to do something, and the formation of redundancy. And that’s exactly what it does!!

Inert function advantages: it can avoid repeated step judgment, redundancy, etc., just a decision, you can directly use, do not have to do useless repeat steps.

Application scenarios of lazy functions: often used in the compilation of function libraries, singleton mode. In a fixed application environment does not change, frequently to use the same judgment logic.

In everyday projects, there are many places where we can apply inertia. For example, if you want to encapsulate a method that gets an element attribute, because earlier versions of Internet Explorer do not support the getComputedStyle method, you do a fault tolerance:

function getCss(element, attr) {
    if ('getComputedStyle' in window) {
        return window.getComputedStyle(element)[attr];
    }
    return element.currentStyle[attr];
}
Copy the code

But every time you go into this method, you have to make a judgment call, and to improve the maintainability of the code, you can save a variable, and then you just go in and check the variable

var flag = 'getComputedStyle' in window
function getCss(element, attr) {
    if (flag) {
        return window.getComputedStyle(element)[attr];
    }
    return element.currentStyle[attr];
}
Copy the code

But every time you execute the getCss function, you need to decide if there is a way to optimize the execution, and this is where inertia comes in.

function getCss(element, attr) { if ('getComputedStyle' in window) { getCss = function (element, attr) { return window.getComputedStyle(element)[attr]; }; } else { getCss = function (element, attr) { return element.currentStyle[attr]; }; } return getCss(element, attr); } getCss(document.body, 'margin'); getCss(document.body, 'padding'); getCss(document.body, 'width');Copy the code

On the first execution, if there is a getComputedStyle method, getCss is assigned to

function (element, attr) {
    return window.getComputedStyle(element)[attr];
};
Copy the code

This function is executed each subsequent time.

conclusion

  • The idea of corrification, using closures, is to store some information in advance for use by subordinate contexts.
  • Combinatorial functions, the processing of function data like a pipe, and then let the data through the pipe to connect, to get the final result.
  • Lazy thinking, not to do the same thing over and over again, and form redundancy.

The three ideas are common high-order function ideas, but also in addition to the callback function, used more of the three high-order functions.

reference

  • zhuanlan.zhihu.com/p/296852112
  • zhuanlan.zhihu.com/p/270634605
  • www.runoob.com/scala/curry…
  • zhuanlan.zhihu.com/p/367460969
  • Taptaq. Making. IO / 2021/05/18 /…
  • www.zhihu.com/search?type…
  • www.liaoxuefeng.com/wiki/102291…