preface

What is this

  • One misconception is that “this” refers to itself. The first step in learning this is to understand that this does not refer to itself, nor to the lexical scope of the function
  • This is bound at run time, not at write time.
  • The binding of this has nothing to do with the position of the function declaration, except how the function is called

This points to the analysis

Call stack and call location

Functions in JS are called one by one, analyze the function call stack and find out the call location, the call location is in the previous function in the current position of the call stack. Ex. :

function fun1(){
    console.log(That's the first function.)
    // call stack fun1
    // The call location is before fun1, which is the global environment
    func2()
}
function fun2(){
    console.log(That's the second function.)
    Call stack fun1 -> fun2
    // The call location is before fun2, which is fun1
    fun3()
}
function fun3(){
    Fun1 -> fun2 -> fun3
    // The call location is one before fun3, which is fun2
    console.log(That's the third function.)
}
fun1() / / call fun1
Copy the code

Binding rules

Analyze which binding rule to apply according to function call location, and the priority of the rule when multiple rules are available.

  1. Default binding: standalone function calls (default rules when no other rules can be applied). A call to a separate function this refers to a global example, even if the call is in another function:

    function test(){
        const a = 'aaa'
        test2()
    }
    function test2(){
        console.log("Test this points to".this.a) // Test this to undefined(in strict mode this to undefined, this.a will throw an error)
    }
    test()
    Copy the code
  2. Implicit binding: Whether the calling location has a context. If owned or contained by an object, called by reference, this refers to that object. Ex. :

    function foo(){
        console.log(this.a)
    }
    const obj = {
        a: 2.fun:foo
    }
    obj.fun() / / 2
    Copy the code

    Note: The object attribute reference chain only works at the last call location:

    function foo(){
        console.log(this.a)
    }
    const obj1 = {
        a: 20.obj2:obj2
    }
    const obj2 = {
        a: 10.fun:foo
    }
    obj1.obj2.fun() //10 points to the last call chain, obj2
    Copy the code

    Note: Implicit binding this is missing. Assigning an object function to a variable by reference and calling the function from the variable is equivalent to calling a separate function. By default, this refers to the global (strictly to undefined) example:

    function foo(){
        console.log(this.a)
    }
    const obj = {
        a: 10.fun:foo
    }
    const test = obj.fun
    test() //undefined
    Copy the code
  3. Displaying the bindings -call, bind, apply changes this to refer to the same use of call as bind, except that call is executed immediately; bind is not executed immediately.

    function foo(){
        console.log(this.a)
    }
    function foo1(){
        console.log(this.a)
    }
    const obj = {
        a:1
    }
    foo.call(obj) / / 1
    foo1.bind(obj)
    foo1() / / 1
    Copy the code

    Note: Once hard-bound, the orientation of this cannot be changed

  4. The new binding creates an internal this for the function via new:

    function foo(){
        console.log(this.a)
    }
    function foo(){
        console.log(this.a)
    }
    const obj = {
        a:1
    }
    Copy the code
  5. Arrow function: Determines this based on outer (function or global) scope. The direction of the arrow function this cannot be changed:

    function foo(){
        return () = > {
            // Inherits from foo
            console.log(this.a)
        }
    }
    const obj1 = {
        a:1
    }
    const obj2 = {
        a:2
    }
    const fun = foo.call(obj1)
    fun.call(obj2) / / 1
    Copy the code

conclusion

If you want to determine the this binding of a running function, you need to find where the function is called directly. Once found, we can apply the following four rules in sequence to determine the object bound to this.

  1. Called by new? Bind to the newly created object.
  2. Called by call or apply (or bind)? Binds to the specified object.
  3. Called by a context object? Bind to that context object.
  4. Default: bind to undefined in strict mode, otherwise bind to global object.