What is the difference between bind, call and apply? How to implement a bind?

Posted by severndigital on Tue, 19 Oct 2021 02:41:59 +0200

1, Function

call, apply and bind are used to change the context of function execution. In short, they are used to change the this point of function runtime

So under what circumstances do you need to change the direction of this? Here is an example

var name="lucy";
const obj={
    name:"martin",
    say:function () {
        console.log(this.name);
    }
};
obj.say(); //martin, this points to the obj object
setTimeout(obj.say,0); //lucy, this points to the window object

As you can see from the above, the say method normally outputs martin

However, we put say in the setTimeout method. It is executed as a callback function in the timer. Therefore, when returning to the main stack, it is executed in the environment of the global execution context. At this time, this points to the window, so it outputs luck

What we actually need is that this points to the obj object. At this time, we need to change this point

setTimeout(obj.say.bind(obj),0); //martin, this points to the obj object

2, Distinction

Let's take a look at the use of apply, call and bind

apply

apply accepts two parameters. The first parameter is the direction of this, and the second parameter is the parameter accepted by the function, which is passed in the form of array

After changing this point, the original function will execute immediately, and this method only temporarily changes this point once

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"Zhang San"
}

fn.apply(obj,[1,2]); // this will become the passed in obj, and the passed in parameter must be an array;
fn(1,2) //  this points to window

When the first parameter is null and undefined, it points to window (in the browser) by default

fn.apply(null,[1,2]); //  this points to window
fn.apply(undefined,[1,2]); //  this points to window

call

The first parameter of the call method is also the point of this, followed by a parameter list

Like apply, the original function will execute immediately after changing this point, and this method only temporarily changes this point once

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"Zhang San"
}

fn.call(obj,1,2); // this will become the passed in obj, and the passed in parameter must be an array;
fn(1,2) //  this points to window

Similarly, when the first parameter is null and undefined, it points to window (in the browser) by default

fn.call(null,[1,2]); //  this points to window
fn.call(undefined,[1,2]); //  this points to window

bind

The bind method is very similar to the call method. The first parameter is also the direction of this. Later, a parameter list is passed in (but this parameter list can be passed in multiple times)

Changing the point of this will not be executed immediately, but will return a function that permanently changes the point of this

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"Zhang San"
}

const bindFn = fn.bind(obj); //  this   It will also become the incoming obj  , bind is not executed immediately. It needs to be executed once
bindFn(1,2) //  this points to obj
fn(1,2) //  this points to window

Summary

As can be seen from the above, the differences among apply, call and bind are as follows:

  • All three can change the point of this object of the function

  • The first parameter of the three is the object to which this points. If there is no parameter or the parameter is undefined or null, it points to the global window by default

  • All three can pass parameters, but apply is an array, call is a parameter list, apply and call are one-time parameters, and bind can be passed in multiple times

  • bind is a function that returns the bound this, such as apply and call   Is executed immediately

3, Realize

The steps to implement bind can be broken down into three parts:

  • Modify this point

  • Dynamic transfer parameters

//  Method 1: transfer function parameters only in bind
fn.bind(obj,1,2)()

//  Method 2: pass function parameters in bind and return functions
fn.bind(obj,1)(2)
  • Compatible with new keyword

The overall implementation code is as follows:

Function.prototype.myBind = function (context) {
    //  Judge whether the calling object is a function
    if (typeof this !== "function") {
        throw new TypeError("Error");
    }

    //  Get parameters
    const args = [...arguments].slice(1),
          fn = this;

    return function Fn() {

        //  Different binding values are passed in according to the calling method
        return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments)); 
    }
}

Topics: Javascript