preface

Corrification, which can be understood as taking some arguments ahead of time, delaying execution, not immediately printing the result, but returning a function that accepts the remaining arguments. Because of this property, it is also called a partially computed function. Cremation is a gradual acceptance of parameters. In the following dissection, you will understand this deeply.

Anti-cremation is a generification process. It allows the function, which is inversely Currified, to take more parameters. The goal is to create a more generic function that can be used by different objects. It has the effect of occupying the magpie nest.

1. Corrification

1.1 example

Add (1)(2, 3)(4)() = 10

There are two key points to note:

  • When an argument is passed in, the code does not execute the output, but remembers it first
  • When an empty argument is passed, it means that the actual operation can be performed

The complete code is as follows:

function currying(fn){
    var allArgs = [];

    return function next(){
        var args = [].slice.call(arguments);

        if(args.length > 0){
            allArgs = allArgs.concat(args);
            return next;
        }else{
            return fn.apply(null, allArgs); }}}var add = currying(function(){
    var sum = 0;
    for(var i = 0; i < arguments.length; i++){
        sum += arguments[i];
    }
    return sum;
});
Copy the code

1.2 Remembering incoming parameters

Since it is the result of delayed calculation, the parameters should be memorized. This is done using closures.

function currying(fn){
    var allArgs = [];

    return function next(){
        var args = [].slice.call(arguments);

        if(args.length > 0){
            allArgs = allArgs.concat(args);
            returnnext; }}}Copy the code

When using var add = currying(…) The add variable already points to the next method. At this point, allArgs is referenced within the next method and therefore cannot be collected by GC. That is, allArgs exists after the assignment statement is executed, forming a closure. By virtue of this feature, you just need to continuously put the received parameters into the allArgs variable for storage. So, when arguments.length > 0, you can put the new arguments you receive into allArgs. Finally, the next function pointer is returned to form a chained call.

1.3 Determine the trigger function execution conditions

If the parameter is null, the result is output. Arguments.length == 0. In addition, since the method of calculating the result is passed as an argument to a currying function, use Apply to execute it. Combining the above considerations, the following complete Currization function can be obtained.

function currying(fn){
    var allArgs = []; // To receive parameters

    return function next(){
        var args = [].slice.call(arguments);

        // Determine whether to perform the calculation
        if(args.length > 0){
            allArgs = allArgs.concat(args); // Collect the incoming parameters and cache them
            return next;
        }else{
            return fn.apply(null, allArgs); // Execute the calculation if the execution condition is met}}}Copy the code

1.4 summarize

Currization, in this case, shows a very clear code of conduct:

  • Parameters are gradually received and cached for later calculation
  • If the calculation is not performed immediately, the execution will be postponed
  • Meet the calculation conditions, the cache parameters, uniformly passed to the execution method

1.5 extensions

Add (1)(2, 3)(4)(5) = 15. Many people here ask the question: how do I know when to execute? In fact, there are ninja skills: valueOf and toString. When obtaining the valueOf the current variable, js will implicitly call valueOf and toString methods to obtain the required value according to the context. So, it’s pretty simple to implement.

function currying(fn){
    var allArgs = [];

    function next(){
        var args = [].slice.call(arguments);
        allArgs = allArgs.concat(args);
        return next;
    }
    // Character type
    next.toString = function(){
        return fn.apply(null, allArgs);
    };
    // A numeric type
    next.valueOf = function(){
        return fn.apply(null, allArgs);
    }

    return next;
}
var add = currying(function(){
    var sum = 0;
    for(var i = 0; i < arguments.length; i++){
        sum += arguments[i];
    }
    return sum;
});
Copy the code

2. Anti-corrification

2.1 example

There are the following light hint classes. Now you want to use its show method alone to print the contents of the new object obj.

/ / light hint
function Toast(option){
  this.prompt = ' ';
}
Toast.prototype = {
  constructor: Toast,
  // Output prompt
  show: function(){
    console.log(this.prompt); }};/ / a new object
var obj = {
    prompt: 'New object'
};
Copy the code

You can do this in an anti-Cremation way

function unCurrying(fn){
    return function(){
        var args = [].slice.call(arguments);
        var that = args.shift();
        returnfn.apply(that, args); }}var objShow = unCurrying(Toast.prototype.show);

objShow(obj); // Print "new object"
Copy the code

2.2 Anti-Corrification behavior

  • What is not mine, is mine
  • Increases the number of parameters received by the anti-Corrification method

In the above example, the toast.prototype. show method was originally private to the Toast class. It has nothing to do with the new obJ. It can be used by OBJ objects when it is inversely currified. It can be used by obj because the context of toast.prototype. show is internally redefined as obj. So I’m changing this with apply. To do this, you need to add the anti-Currified objShow method parameters.

2.3 Another realization of anti-Corrification

Function.prototype.unCurrying = function(){
    var self = this;
    return function(){
        return Function.prototype.call.apply(self, arguments); }}/ / use
var objShow = Toast.prototype.show.unCurrying();
objShow(obj);
Copy the code

The difficulty of here is to understand the Function. The prototype. Call. Apply (self, the arguments); . It can be broken down into two steps:

1) Function. The prototype. Call. Apply (…). The resolution of

Call function.apply (…) . This way, it’s a lot clearer. The this pointer to callFunction is changed to self by apply. Then call callFunction -> callFunction(arguments)

2) callFunction(arguments

The call method, the first argument, is used to specify this. CallFunction (arguments) -> callFunction(arguments[0], arguments[1-n]). It follows from this that the first argument, after the anti-Curryification, is used to specify that this refers to.

If you use apply(null, arguments), null objects have no call method and will return an error.

Third, in actual combat

3.1 Determining the type of variables (anti-Corrification)

var fn = function(){};
var val = 1;

if(Object.prototype.toString.call(fn) == '[object Function]') {console.log(`${fn} is function.`);
}

if(Object.prototype.toString.call(val) == '[object Number]') {console.log(`${val} is number.`);
}
Copy the code

The above code, using the inverse Cremation, could be written as follows:

var fn = function(){};
var val = 1;
var toString = Object.prototype.toString.unCurrying();

if(toString(fn) == '[object Function]') {console.log(`${fn} is function.`);
}

if(toString(val) == '[object Number]') {console.log(`${val} is number.`);
}
Copy the code

3.2 Listening Events (Currified)


function nodeListen(node, eventName){
    return function(fn){
        node.addEventListener(eventName, function(){
            fn.apply(this.Array.prototype.slice.call(arguments));
        }, false); }}var bodyClickListen = nodeListen(document.body, 'click');
bodyClickListen(function(){
    console.log('first listen');
});

bodyClickListen(function(){
    console.log('second listen');
});

Copy the code

Using Currification, optimizations listen for DOM node events. AddEventListener does not need to be written every time.

Afterword.

In fact, anti-Corrification is the same as generics, but with a few conceptual differences. Just understand the thinking.


Friends who like my articles can follow me in the following ways:

  • “Star” or “watch” my GitHub blog
  • RSS subscribe to my personal blog:Mr. Wang’s base