Bind, call, apply

Call, apply, and bind are used to change the context in which a function is executed.

Sometimes, however, there is no need to change the direction of this, for example, as follows:

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

Copy the code

As you can see above, the say method normally prints xiaohong

But we put say in the setTimeout method, which is executed as a callback function in the timer, so back to

The main stack is executed in the global execution context, and this points to the window, so xiaoming is output

What we really need is for this to point to an obj object, and that’s when we need to change this point

setTimeout(obj.say.bind(obj),0); //xiaohong, this points to obj
Copy the code

(2) Bind, call, apply

1: apply

Apply takes two arguments, the first being a reference to this and the second being an argument accepted by the function as an array

The original function executes immediately after changing the this pointer, and this method only temporarily changes the this pointer once

function fn(. args){
    console.log(this,args);
}
let obj = {
    myname:"Know the Fox"
}

fn.apply(obj,[1.2]); // This becomes obj passed in, and the argument passed in must be an array;
fn(1.2) // This points to window
Copy the code

The results are as follows:

fn.apply(null[1.2]); // This points to window
fn.apply(undefined[1.2]); // This points to window
Copy the code

When the first argument is null, undefined, the default point is window(in the browser).

2:call

The first argument to the call method also points to this, followed by a list of arguments

As with Apply, the original function is executed immediately after changing this, and this method only temporarily changes this once

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

        fn.call(obj, 1.2); // This becomes obj passed in, and the argument passed in must be an array;
        fn(1.2) // This points to window
Copy the code

Similarly, when the first argument is null, undefined, the default point is window(in the browser).

3:bind

The bind method is similar to call in that the first argument points to this and is followed by a list of arguments (although this argument list can be passed multiple times).

Changing the this pointer is not executed immediately, but returns a function that permanently changes the this pointer

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

        const bindFn = fn.bind(obj); // This will also become the obj passed in. Bind is not called immediately and needs to be called once
        bindFn(1.2) // this points to obj
        fn(1.2) // This points to window
Copy the code

As can be seen from the above, the difference between apply, call and bind is that:

  • All three can change the function’s this object
  • The first argument in all three cases is the object to which this refers. If there is no argument or the argument is undefined or null, it points to the global window by default
  • All three can be passed, but apply is an array, call is a list of parameters, and apply and call are passed once, while bind can be passed multiple times
  • Bind is a function that returns after this is bound, and apply and call are executed immediately

Three, implementation,

  • Modify this to point to
  • Dynamic transfer parameter
// Method 1: Pass function arguments only in bind
fn.bind(obj,1.2) ()// Method 2: Pass function arguments in bind and return functions
fn.bind(obj,1) (2)
Copy the code
  • Compatible with new keyword

    The overall implementation code is as follows:

    Function.prototype.myBind = function (context) {
      // Determine 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 depending on how the call is made
          return fn.apply(this instanceof Fn ? newfn(... arguments) : context, args.concat(... arguments)); }}Copy the code