Writing in the front

As a ambitious front-end siege lion, it is necessary to master several advanced programming skills. Learning these skills will make our development work more efficient and more comfortable. This article will introduce three tips:

  • Application of lazy loading functions

  • Application of currization of functions

  • Compose calls the function flat

Lazy loading function

Our code must contain a large number of if statements that take some time to execute. In one case, the first time we go into the if branch, we execute that part of the code, and then the second time we do the same branch, we execute that part of the code again. In this case, the code will execute slower, so if we only have an if branch, the code will execute faster. To make code execute faster, this is where lazy loading functions are used. Next, look at an example of DOM event binding:

function emit(element, type, func) {
    if(element.addEventListener) {
        element.addEventListener(type, func, false)}else if(element.attachevent) {// IE6, 7, 8 element.attachevent ("on" + type, func)
    } else {
        element["on" + type] = func; }}Copy the code

In the example above, determine whether the browser supports each method, going into a different branch, and thus binding events differently. If you bind multiple times, you will enter the same if branch multiple times to execute the code. In fact, in the same browser environment, bind multiple times, only need to judge once to complete the purpose. So, you need to apply the lazy load function

function emit(element, type, func) {
    if(element.addEventListener) {
        emit = function(element, type, func) {
            element.addEventListener(type, func, false)}}else if(element.attachEvent) {
        emit = function(element, type, func) {
            element.attachEvent("on" + type, func)
        }
    } else {
        emit = function(element, type, func) {
            element["on" + type] = func;
        }
    }
    emit(element, type, func);
}
Copy the code

In the optimized code, the emit is reassigned after the first execution goes to a branch to execute that part of the code. This ensures that only one if is executed for multiple calls and the code executes faster.

Application of currization of functions

In JavaScript Advanced Programming, it is explained as follows: The topic closely related to function binding is function currization, which is used to create a function that has one or more parameters set. The basic approach to function curryification is the same as function binding: use a closure to return a function. Let’s start with an example:

function add(num1, num2) {
    return num1 + num2;
}

function curried(num2) {
    returnadd(5, num2); } console.log(curried(2)); / / 7Copy the code

This code has two functions, add returns the sum of two arguments, and Curried returns the sum of 5 and the arguments received after calling add. This curried function is what we call a big function that returns a small function, but it’s not a Corrified function.

A Currified function is usually created dynamically by calling another function and passing it the function to be currified and the necessary arguments. Now, let’s write a general way of currizing functions

functioncurry(fn) { var args = Array.prototype.slice.call(arguments, 1); // Get the argument after the first argumentreturn function() {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        returnfn.apply(null, finalArgs); // call fn}}function add(num1, num2) {
    returnnum1 + num2; } console.log(curry(add, 5, 12)()); // 17 console.log(curry(add, 6, 7)()); / / 13Copy the code

The Currization function can also be used to construct bind()

/** * @params * fn: function to be executed * context: this to be changed to refer to */function bind(fn, context) { context = context || window; / / if you don't pass the context parameter, make it as a window var args = Array. The prototype. Slice. The call (the arguments, 2); // Get the argument after the second argumentreturn function() {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        returnfn.apply(context, finalArgs); }}Copy the code

Take a look at the results:

var obj = {
    x: 1
}
function fn() {
    return this.x + 2;
}

btn.onclick = function() {
    console.log(bind(fn, obj)())      // 3
}
Copy the code

The bind function successfully changed this to obj. But we put our own bind in the prototype in order to call just like the bind in the Function prototype

(function(proto) {
    function bind(context) { context = context || window; / / if you don't pass the context parameter, make it as a window var args = Array. The prototype. Slice. The call (the arguments, 1); // Get the argument after the second argumentreturn function() {
            var innerArgs = Array.prototype.slice.call(arguments);
            var finalArgs = args.concat(innerArgs);
            return fn.apply(context, finalArgs);
        }
    }
    proto.bind = bind;
})(Function.prototype)
Copy the code

So let’s see what happens

var obj = {
    x: 1
}
function fn(y) {
    return this.x + y;
}

btn.onclick = function() {
    console.log(fn.bind(obj, 3)())     // 4
}
Copy the code

So that’s bind using the currified handwriting function. In addition, there are some source code also use the function corrification, such as redux and so on.

Next, let’s look at an interview question: Implementing the Add function

add(1); //1 add(1)(2); //3 add(1)(2)(3); / / add 6 (1) (2, 3); / / 6 add (1, 2) (3); / / 6 add (1, 2, 3); / / 6Copy the code
function currying(anonymous, length) {
    return functionadd(... Args) {// return add, accept arguments... Args // If the length of the received argument is greater than the number of function arguments, the receive function is executed directlyif (args.length >= length) {      
            returnanonymous(... args); } // Otherwise, call currying recursively, returning a new anonymous function and a new lengthreturncurrying(anonymous.bind(null, ... args), length - args.length); }} // The count argument is the total number of arguments passed and needs to be changed each time this function is calledlet add = currying(functionanonymous(... args) {return args.reduce((x, y) => x + y);
}, count);
Copy the code

Let’s take a look at the effect:

console.log(add(1)); // Change the count parameter to 1 and output 1 console.log(add(1)(2)); // Change the count parameter to 2 and output 3 console.log(add(1)(2)(3)); // change count to 3 and output 6 console.log(add(1)(2,3)); // change count to 3 and output 6 console.log(add(1,2)(3)); // change count to 3 and output 6 console.log(add(1,2,3)); Console. log(add(5, 6, 7, 8)) // Change the count parameter to 3, and the output is 6Copy the code

To sum up, we have finished writing the add function, there is not necessarily only one solution to a problem, this problem is the same, there are many solutions, welcome to discuss in the comment section ~

Compose calls the function flat

Before, we heard about array flattening. Array flattening means turning a multilevel array into a single layer. Similarly, calling a function flattening means turning a deep function into a single layer.

var fn1 = function(x) {
    return x + 5;
}

var fn2 = function(x) {
    return x + 6;
}

var fn3 = function(x) {
    returnx + 7; } console.log(fn3(fn2(fn1(5)))); / / 23Copy the code

In the above example, the result of function fn1 is passed to fn2, which is passed to fN3, and finally the result of fN3 is printed. For example, we want to implement the compose function, which is composed:

Compose (fn1, fn2, fn3)(5) // equivalent to fn3(fn2(fn1(5))Copy the code

Let’s start implementing:

function compose() {
    var funcs = Array.prototype.slice.call(arguments);
    return function() {
        var args = Array.prototype.slice.call(arguments);
        var len = funcs.length;
        if(len === 0){
            return args[0];
        } 
        if(len === 1) {
            returnfuncs[0](... args) }return funcs.reduce(function(x, y) {
            return typeof x === "function"? y(x(... args)) : y(x) }) } }Copy the code

Take a look at the results:

console.log(compose(fn1, fn2, fn3)(5)); // 23 console.log(compose(fn1)(5)); // 10 console.log(compose()(5)); / / 5Copy the code

The output is in line with our expectations, indicating that the compose function we encapsulated is correct. However, this is not the only way for the compose function to be encapsulated. Let’s take a look at the compose function in Redux

export default functioncompose(... funcs) {if(funcs.length === 0) {// When the number of functions passed is 0, the argument is returned directlyreturn arg => arg
    }
    
    if(funcs.length === 1) {// When the number of functions passed is 1, the function is executed directlyreturnFuncs [0]} // When the number of functions passed in is not 0 and 1, the function is executed from back to frontreturnfuncs.reduce((a, b) => (... args) => a(b(... args))) }Copy the code

The compose function can be composed in either of the two ways. The first way is easy to understand. The second way is a bit simpler, and requires you to think about the execution logic of the compose function

The last

Advanced programming skills are necessary in the development, master is more good ~ think the article is helpful to you, you can give this article a thumbs up ~ if the article is not correct, but also hope that we point out ~ we learn together, common progress ~

Finally, share my public number “web front end diary” ~ we can pay attention to a wave ~