This four binding principles

The default binding

The default is to point to the calling object

function foo() {    
    console.log(this.a);
}
var a = 2;
foo(); / / 2
Copy the code

A variable declared in global scope (such as var a = 2) is an attribute of the same name for the global object. They are essentially the same thing, not copied, like two sides of a coin.

Next we can see that this.a is resolved to the global variable a when foo() is called. Why is that? Because in this case, the default binding for this is applied when the function is called, this points to the global object.

So how do we know that the default binding is applied here? You can see how foo() is called by analyzing the call location. In the code, foo() is called directly with an undecorated function reference, so only the default binding can be used and no other rules can be applied.

If strict mode is used, the default binding is not available for global objects, so this is bound to undefined

function foo() {
    console.log(this.a);
}
var a = 2;
(function () {
    "use strict";
    foo(); / / 2}) ();Copy the code

There is a subtle but very important detail here, although the binding rules for this depend entirely on where it is called, the default binding can only be bound to a global object if foo() is not running in strict mode; Strictly independent of where foo() is called

Implicit binding

Another rule to consider is whether the calling location has a context object or is owned or contained by an object, although this can be misleading

function foo() {
    console.log(this.a);
}
var obj = {
    a: 2.foo: foo,
};
obj.foo(); / / 2
Copy the code

The first thing to notice is how foo() is declared and then added to OBj as a reference property. But whether defined directly in OBj or defined first and then added as a reference property, this function is not strictly an OBj object.

However, the call location references the function using the OBJ context, so you can say that the obJ object “owns” or “contains” the function when it is called.

No matter what you call this pattern, when foo() is called, its foothold does point to an obj object. When a function reference has a context object, the implicit binding rule binds this in the function call to that context object. Because this is bound to obj when foo() is called, this.a and obj.a are the same

Explicitly bound

function foo() {
    console.log(this.a);
}
var obj = {
    a: 2}; foo.call(obj);/ / 2
Copy the code

“All” functions in JavaScript have some useful features that can be used to solve this problem. Specifically, you can use the call(..) of the function. And the apply (..) Methods.

Strictly speaking, JavaScript hosting environments sometimes provide very special functions that don’t have these two methods. However, such functions are very rare, and most JavaScript functions and all the functions you create can use call(..). And the apply (..) Methods.

call apply bind

From a blank look to complete understanding

  • Call (), apply(), and bind() are all used to redefine this!

Obj. MyFun. Call (db);// Dema is 99 years oldobj.myFun.apply(db);// Dema is 99 years oldobj.myFun.bind(db)();// Dema is 99 years old
Copy the code
  • Compare call, bind, and apply parameters

obj.myFun.call(db,'chengdu'.'Shanghai');// Dema is 99 years old and comes from Chengdu to Shanghai
obj.myFun.apply(db,['chengdu'.'Shanghai']); // Dema is 99 years old and comes from Chengdu to Shanghai
obj.myFun.bind(db,'chengdu'.'Shanghai') ();// Dema is 99 years old and comes from Chengdu to Shanghai
Copy the code
  • summary

  • Call, bind, and apply all take this as their first argument to the object.

  • Here comes the second parameter difference:

Obj. Myfun. call(db,’ db ‘,… , ‘string’).

All parameters of apply must be passed to obj.myfun. apply(db,[‘ chengdu ‘,… ‘string’]) in an array.

Bind takes the same arguments as Call, except that it returns a function.

The new binding

function foo(a) {
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a); / / 2
Copy the code

When a function is called with new, or when a constructor call occurs, the following operations are performed automatically.

  1. Create (or construct) a brand new object.

  2. This new object will be connected by the implementation prototype.

  3. This new object is bound to the function call’s this.

  4. If the function returns no other object, the function call in the new expression automatically returns the new object.

Call foo(..) with new , we construct a new object and bind it to foo(..). Call to this. New is the last way to influence the behavior of the this binding when a function is called, and we call it the new binding.

This in the function’s self-execution points to the window

Because when the function executes, it’s actually window that calls it, which is window. The function name (); So, the this inside refers to the object that is currently calling this function, which is the window.

<input type="button" value="modify" οnClick="changeContent()" />
Copy the code

The changeContent function written on the element onclick is equivalent to a direct call to the function, which uses this to point to the global object Window, not to the element

<input type="button" value="Change" οnClick="changeContent(this)" />
Copy the code

The “this” here refers to the input tag, and the parameter that you want to set is the one that’s currently in the object if you don’t set the parameter just $(this) is the Windows object

About this pointing in setInterval and setTimeout

var num = 0;
function Obj() {
    this.num = 1;
    this.getNum = function () {
        console.log(this.num);
    };
    this.getNumLater = function () {
        setTimeout(function () {
        console.log(this.num);
        }, 1000);
    };
}
var obj = new Obj();
obj.getNum(); //1 prints obj.num with a value of 1
obj.getNumLater(); //0 prints window.num with a value of 0
Copy the code

As you can see from the above example, this in the setTimeout function refers to the window object, because the code called by setTimeout() runs in a completely separate execution environment from that of the function. This causes the code to include the this keyword pointing to the Window (or global) object. For details, see MDN setTimeout

  1. Store the this of the current object as a variable. The function inside the timer accesses the variable using a closure, as follows:
var num = 0;
function Obj() {
    var that = this; // Store this as a variable where this refers to obj
    this.num = 1;
    this.getNum = function () {
    console.log(this.num);
};
this.getNumLater = function () {
    setTimeout(function () {
        console.log(that.num); // Use the closure to access that, which is a pointer to obj
        }, 1000);
    };
}
var obj = new Obj();
obj.getNum(); //1 prints obj.num with a value of 1
obj.getNumLater(); //1 prints obj.num with a value of 1
Copy the code
  1. Use the bind()(example) cell() apply() method
var num = 0;
function Obj() {
    this.num = 1;
    this.getNum = function () {
        console.log(this.num);
    };
    this.getNumLater = function () {
        setTimeout(function () {
        console.log(this.num);   
        }.bind(this),1000); // Bind this to the function with bind()
    };
}
var obj = new Obj();
obj.getNum(); //1 prints obj.num with a value of 1
obj.getNumLater(); //1 prints obj.num with a value of 1

Copy the code
  1. Arrow function
var num = 0;
function Obj() {
    this.num = 1;
    this.getNum = function () {
        console.log(this.num);
    };
    this.getNumLater = function () {
        setTimeout(() = > {
            console.log(this.num);
        }, 1000); // This in the arrow function always points to the outer caller, Obj
    };
}
var obj = new Obj();
obj.getNum(); //1 prints obj.num with a value of 1
obj.getNumLater(); //1 prints obj.num with a value of 1
Copy the code

The arrow function in ES6 completely fixes the pointing of this, which always points to the lexical scope, the outer caller obj, so this can be easily fixed using the arrow function.