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.
-
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
-
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
-
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
-
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
-
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.
- Called by new? Bind to the newly created object.
- Called by call or apply (or bind)? Binds to the specified object.
- Called by a context object? Bind to that context object.
- Default: bind to undefined in strict mode, otherwise bind to global object.