There are a lot of confusing things in JavaScript, however, because these things make JavaScript more powerful. For example, prototype chains, closures, etc., including this mechanism, are everywhere.

This binding rule

This mechanism has four kinds of binding rules: default binding, implicit binding, explicit binding, new binding, respectively corresponding to the four types of function call: direct function call, object method call, indirect call, constructor call.

** In non-strict mode: ** this refers to an object

The default binding

Global environment, this refers to window

console.log(this= =window);//true
Copy the code

This refers to the window

function fn (){
    console.log(this= =window);//true
}
Copy the code

Call the nested function, this pointing to the window

function fn (){
    function test(){
        console.log(this= =window);//true
    }
    test();
}
fn();
Copy the code

This is in the non-strict mode.

In strict mode, the default binding is different. In non-strict mode, this is bound to the parent scope, and in strict mode, it is not bound to the window object

function fn(){
    'use strict';
    console.log(this);//undefined
}
fn();
Copy the code
Implicit binding

Calls the method on the object, where this refers to the object itself

let obj = {
    count:1.getCount(){
        console.log(this);//obj
        console.log(this.count);/ / 1
    }
}
obj.getCount();
Copy the code

The above code is equivalent to

let obj = {
    count:1.getCount(){
        console.log(obj);//obj
        console.log(obj.count);/ / 1
    }
}
obj.getCount();
Copy the code
Explicitly bound

Use call(),apply(), and bind() to force this to change

let count = 2
let obj = {
    count:1.getCount(){
        console.log(this.count);/ / 2
    }
}

obj.getCount.call(this);
Copy the code
let obj1 = {
    a:'obj1 '}, obj2 = {a:'obj2' } function fn(){ console.log(this.a); } fn.call(obj1); //obj1 fn.call(obj2); //obj2Copy the code
let obj = {
    a:"obj"
}
let a = 'a'
function fn (param){
    console.log(this.a);
    console.log(param);
}
fn()//a
fn.call(obj,'call')//obj,call
fn.apply(obj,['apply'])// obj , ['apply']

let fnBind = fn.bind(obj);
fnBind('bind');//obj , 'bind'


Copy the code

Call (),apply(), and bind() can all change this direction

call(),apply()withbind()The difference between

Bind (obj) returns a new function already bound to this. A separate call will be executed

let obj = {
    name:'bind'
}
function fn (){
    console.log(this.name);
}
let fn1 = fn.bind(obj);
fn1();//bind
Copy the code

Call (),apply() binds this and executes the method

let obj = {
    name:'obj'.getName(){
        console.log(this.name); }}let obj1 = {
    name:'call'
}
let obj2 = {
    name:'bind'
}

obj.getName.apply(obj2)//bind
obj.getName.call(obj1);//call
Copy the code
apply()withcall()The difference between

The difference is that the arguments passed are in the form of arrays accepted by apply()

The new binding

A function or method is called with new, which is called as a constructor.

function Fn (){
    this.name = "fn";
}
let f = new Fn();
console.log(f);//{name: "fn"}
Copy the code

You don’t normally use a return when you use constructors. When we call new, internally we’re going to create a this object and attach the property that we added to this object and return it.

If you return a raw value in a constructor and then bind it to new, the constructor will ignore the original value, create an object and return it

function Fn(){
    this.name = "fn";
    return 1;
}
let f = new Fn();
console.log(f);//{name: "fn"}
Copy the code

If the constructor returns an object, the new binding does not create it internally, but simply returns the object

function Fn(){
    this.name = "fn";
    return {
        name:'object'.age:20}}let f = new Fn ();
console.log(f);//{name: "object", age: 20}
Copy the code

This binding is missing

Alias loss implicit binding

var name = 'window';
let obj = {
    name:'obj'.getName(){
        return this.name; }}let getName = obj.getName;
console.log(getName());//'window'

Copy the code

The callback loses implicit binding

const WITH_TIME = 1000;
let name = "window";
let obj = {
    name:"obj".getName(){
        console.log(this.name); }}setTimeout(obj.getName,WITH_TIME);//window
Copy the code
This lost fix

Explicitly bind() to this

var name = 'window';
let obj = {
    name:'obj'.getName(){
        return this.name; }}let getName = obj.getName.bind(obj);
console.log(getName());//'obj'
Copy the code

Es6 Haircut function

const WITH_TIME = 1000;
let name = "window";
let obj = {
    name:"obj".getName(){
       setTimeout(() = >{
           console.log(this.name);//'obj'
       },WITH_TIME);
    }
}
obj.getName();

Copy the code

This binding priority

Explicit binding VS implicit binding
function getName(){
    console.log(this.name);
}
let obj1 = {
    name:"javaScipt".getName:getName
}
let obj2 = {
    name:'Python'.getName:getName
}

obj1.getName();//'javaScipt'
obj2.getName();//'Python'

obj1.getName.call(obj2);//Python
obj2.getName.call(obj1);//javaScipt
Copy the code

Conclusion: Explicit binding has higher priority than implicit binding

Implicit binding VSnewThe binding
function getName(){
    console.log(this.name);
}
let obj1 = {
    name:"javaScipt".getName:getName
}
let obj2 = {
    name:'Python'.getName:getName
}

obj1.getName();//'javaScipt'
obj2.getName();//'Python'

let o1 = new obj1.getName();//undefined
let o2 = new obj2.getName();//undefined
Copy the code

Conclusion: New binding priority size implicit binding

Explicit binding VSnewThe binding
function getName(){
    console.log(this.name);
}
let obj1 = {
    name:"javaScipt".getName:getName
}
let obj2 = {
    name:'Python'.getName:getName
}

obj1.getName.call(obj2);//'Python'
obj2.getName.call(obj1);//'javaScitp'

let o1 = new obj1.getName.call(obj2);//obj1.getName.call is not a constructor
let o2 = new obj2.getName.call(obj1);//obj2.getName.call is not a constructor
Copy the code

Error: Explicit binding and new binding cannot be shared

The bind ()?

function getName(){
    console.log(this.name);
}
let obj1 = {
    name:"javaScipt".getName:getName
}
let obj2 = {
    name:'Python'.getName:getName
}

let f1 = obj1.getName.bind(obj2);
let f2 = obj2.getName.bind(obj1);
f1();//'Python'
f2();//'javaScitp'

let b1 =obj1.getName.bind(obj2);
let b2 = obj2.getName.bind(obj1);
let o1 = new b1();//undefined
let o2 = new b2();//undefined
Copy the code

Bind () returns a function that changes what this refers to, and then new calls, and this changes again

Conclusion: New binding has higher priority than explicit binding

Refer to the article

13. Close reading of The Confusion Caused by This

The articles

After reading this article, let your JS elegant a grade

How to configure Nginx for multiple Vue projects

Heavy learning Vue Components

Front-end Vue+ AXIos realization of Ali Cloud OSS file upload (server signature direct transmission)

Front-end strange technology clever JS debugging