In depth understanding of JavaScript series (49) : Function mode (part 1)

  • 2020-05-10 17:44:42
  • OfStack

introduce

This article focuses on the techniques used in Function (part 1). You can write a lot of very interesting code using Function features, including callback patterns, configuration objects, return functions, distributions, and currification (Currying).

The callback function

In JavaScript, when one function A is taken as one of the parameters of another function B, the function A is called a callback function, that is, A can be executed within the period of the function B (start, middle, end).

For example, there is a function that generates node


var complexComputation = function () { /* Process internally and return 1 a node*/};

There is an findNodes function declaration that finds all the nodes, and then executes the code through an callback callback.

var findNodes = function (callback) {
var nodes = []; var node = complexComputation(); // If the callback function is available, execute it
if (typeof callback === "function") {
callback(node);
} nodes.push(node);
return nodes;
};

As for the definition of callback, we can define it in advance to use:


// define callback
var hide = function (node) {
node.style.display = "none";
}; // To find the node And hide everything node
var hiddenNodes = findNodes(hide);

You can also use the anonymous definition directly when calling, as follows:


// Use anonymous function definitions callback
var blockNodes = findNodes(function (node) {
node.style.display = 'block';
});

The most commonly used jQuery calls are probably ajax method calls. By defining callback on done/faild, callback can be processed one step further if the ajax call succeeds or fails. The code is as follows (this code is based on jquery1.8) :

var menuId = $("ul.nav").first().attr("id");
var request = $.ajax({
  url: "script.php",
  type: "POST",
  data: {id : menuId},
  dataType: "html"
}); // Callback handling on successful invocation
request.done(function(msg) {
  $("#log").html( msg );
}); // Callback handling when the call fails
request.fail(function(jqXHR, textStatus) {
  alert( "Request failed: " + textStatus );
});

A configuration object

If a function (or method) has only one argument and the argument is an object literal, we call this pattern the configuration object pattern. For example, the following code:


var conf = {
    username:"shichuan",
    first:"Chuan",
    last:"Shi"
};
addPerson(conf);

Then, within addPerson, you can use the value of conf at will. 1 is generally used for initialization. For example, ajaxSetup in jquery is also implemented in this way:

// Set the initial value in advance
$.ajaxSetup({
   url: "/xmlhttp/",
   global: false,
   type: "POST"  }); // And then call
 $.ajax({ data: myData });
 

In addition, many plug-ins of jquery also have this form of pass parameter, but you can also pass it without using the default value when it is not passed.

Returns the function

Return function refers to a new function whose return value of one function is another function or which can be flexibly created according to specific conditions. The sample code is as follows:


var setup = function () {
    console.log(1);
    return function () {
        console.log(2);
    };
}; // call setup function
var my = setup(); // The output 1
my(); // The output 2
// Or call it directly
setup()();

Or you can take advantage of the closure feature and record a private counter number in the setup function, incrementing the counter with each call. The code is as follows:

var setup = function () {
    var count = 0;
    return function () {
        return ++count;
    };
}; // usage
var next = setup();
next(); // return 1
next(); // return 2
next(); // return 3

Partial application

In this case, the partial application is to pass in the parameters separately. Sometimes the operation of 1 series may have one or more parameters that are exactly the same, so we can define a partial function first, and then execute the function (pass in the remaining parameters).

For example, the code is as follows:


var partialAny = (function (aps) {     // This function is the result of your self-executing function expression, and it's assigned to partialAny variable
    function func(fn) {
        var argsOrig = aps.call(arguments, 1);
        return function () {
            var args = [],
                argsPartial = aps.call(arguments),
                i = 0;             // The original set of variables,
            // If the parameter is partialAny._ Placeholder, then use 1 The corresponding values of the function parameters
            // Otherwise use the value in the original argument
            for (; i < argsOrig.length; i++) {
                args[i] = argsOrig[i] === func._
                            ? argsPartial.shift()
                            : argsOrig[i];
            }             // If there are any extra parameters, add them to the tail
            return fn.apply(this, args.concat(argsPartial));
        };
    }     // Used for placeholder Settings
    func._ = {};     return func;
})(Array.prototype.slice);

The usage is as follows:


// Define the processing function
function hex(r, g, b) {
    return '#' + r + g + b;
} // Define partial functions , will hex The first 1 A parameter r As a constant parameter value ff
var redMax = partialAny(hex, 'ff', partialAny._, partialAny._); // The new function redMax Is called as follows, just pass in 2 Three parameters:
console.log(redMax('11', '22')); // "#ff1122"

If you think partialAny._ is too long, use instead.

var __ = partialAny._; var greenMax = partialAny(hex, __, 'ff');
console.log(greenMax('33', '44')); var blueMax = partialAny(hex, __, __, 'ff');
console.log(blueMax('55', '66')); var magentaMax = partialAny(hex, 'ff', __, 'ff');
console.log(magentaMax('77'));

It's a lot simpler to use.

Currying

Currying is a feature of functional programming that converts the processing of multiple parameters into the processing of a single parameter, similar to chained calls.

Take a simple example of the add function:


function add(x, y) {
    var oldx = x, oldy = y;
    if (typeof oldy === "undefined") { // partial
        return function (newy) {
            return oldx + newy;
        }
    }
    return x + y;
}

In this way, there can be many ways to call, such as:

// test
typeof add(5); // "function"
add(3)(4); // 7 // You can call it like this
var add2000 = add(2000);
add2000(10); // 2010

Next, let's define a more general currying function:

// The first 1 Are the parameters to be applied function In the first 2 Four is the minimum number of parameters that need to be passed in
function curry(func, minArgs) {
    if (minArgs == undefined) {
        minArgs = 1;
    }     function funcWithArgsFrozen(frozenargs) {
        return function () {
            // Optimizes the processing and returns the function itself if there are no arguments when called
            var args = Array.prototype.slice.call(arguments);
            var newArgs = frozenargs.concat(args);
            if (newArgs.length >= minArgs) {
                return func.apply(this, newArgs);
            } else {
                return funcWithArgsFrozen(newArgs);
            }
        };
    }     return funcWithArgsFrozen([]);
}

In this way, we can define our business behavior at will, such as defining addition:


var plus = curry(function () {
    var result = 0;
    for (var i = 0; i < arguments.length; ++i) {
        result += arguments[i];
    }
    return result;
}, 2);

There are so many different ways to use it.

plus(3, 2) // Normal call
plus(3) // Partial application, return 1 Function (the return value is 3+ The parameter value)
plus(3)(2) // Full application (return 5 )
plus()(3)()()(2) // return 5
plus(3, 2, 4, 5) // Multiple parameters can be received
plus(3)(2, 3, 5) // In the same way

Here is an example of subtraction

var minus = curry(function (x) {
    var result = x;
    for (var i = 1; i < arguments.length; ++i) {
        result -= arguments[i];
    }
    return result;
}, 2);

Or if you want to swap the order of the arguments, you can define it this way

var findNodes = function (callback) {
var nodes = []; var node = complexComputation(); // If the callback function is available, execute it
if (typeof callback === "function") {
callback(node);
} nodes.push(node);
return nodes;
};
8

conclusion

Function in JavaScript has a number of special functions, and you can use closures and the arguments parameter feature to implement many different tricks. In the next article, we will continue with the initialization techniques of Function.


Related articles: