This is not easy to understand, but very, very, very important. If you have any questions please comment, the author will reply.

An overview of the

Each function’s this is bound at call time, depending entirely on where the function is called (that is, how the function is called).

Several scenarios in which a function is called

  1. The function is called normally;
  2. Functions are called as methods;
  3. The function is invoked forcibly using call/apply;
  4. The function is called as a constructor;

We will combine these four usage scenarios to analyze the this direction.

Default binding (functions are called normally)

Type 2. This points to the window.

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

What about the strict model?

Strictly, this refers to undefined. Classes in ES6 are in strict mode by default.

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

What about indirect calls?

Type 2. Strict mode only affects the this reference when called directly.

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

conclusion

When the function is normally called, this points to the window; Point to undefined in strict mode.

Implicit binding (function called as method)

Print 1. So this points to obj.

function foo() {
    console.log(this.a)
}
const obj = {
    a: 1.foo: foo,
}
obj.foo();
Copy the code

Multiple calls print 1. Multiple calls, this pointing to the nearest level

function foo() {
    console.log(this.a)
}
const obj = {
    a: 1.foo: foo,
}

const obj2 = {
    a: 2.obj: obj,
}
obj2.obj.foo();
Copy the code

After the method is assigned, it is called to print 2. In this case, fn is foo itself, just like the default binding.

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

Called as a function to print 2. As an argument fn is foo itself, as is the default binding.

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

conclusion

The function is called as a method, pointing to the object closest to the calling function.

Explicitly bound

Use apply, call, and bind to enforce the this pointer and pass arguments to the original function.

The apply, call

Print 3 with call and 4 with apply. Prove that this refers to obj1 and obj2, respectively.

The difference between apply and call is in parameters: the second parameter of apply is array, and all parameters of call are arranged directly.

function foo(a, b) {
    console.log(this.c + a + b)
}
var obj1 = {
    c: 1,}var obj2 = {
    c: 2,
}
foo.call(obj1, 1.1)
foo.apply(obj2, [1.1])
Copy the code

bind

Type 3. Bind is pre-bound. It does not point to a call, but returns a function that is waiting to be called again. Not only does this point change, but it also consolidates the parameters of the two calls. You can go and look at the currization of the function.

function foo(a, b) {
    console.log(this.c + a + b)
}
var obj = {
    c: 1,}var bindFoo = foo.bind(obj, 1);
bindFoo(1)
Copy the code

conclusion

Apply, call, and bind can all change this, but in different ways.

The new binding

Print 1. This refers to the new object generated after new.

function foo() {
    this.a = 1;
}
const obj = new foo();
console.log(obj.a)
Copy the code

Four key processes for New:

  1. Create a brand new object.
  2. The new object will be connected by the implementation [[prototype]].
  3. The 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.

Now you just need to understand steps 1, 3, and 4. Step 2 will be followed by a separate article, which is the core content of JS.

conclusion

When the function is called by new, this points to the new object generated after new.

priority

Now let’s talk about, what is the priority of both situations? First, the default binding has the lowest priority, so there is no need to compare.

Implicit and explicit comparison

Type 2. Prove explicit binding > implicit binding.

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

New and implicit comparison

Observe the print result. Prove new binding > implicit binding.

function foo() {
    console.log(this.a); // undefined
    this.a = 2;
}
var obj = {
    a: 1.foo: foo
}
const newObj = new obj.foo();
console.log(newObj) // { a: 2 }
Copy the code

New and explicit comparison

New cannot be used with apply and call. Let’s experiment with BIND: look at the print. Prove new binding > explicit binding.

function foo() {
    console.log(this.a); // undefined
    this.a = 2;
}
var obj = {
    a: 1,}const bindFoo = foo.bind(obj)
const newObj = new bindFoo();
console.log(newObj) // { a: 2 }
Copy the code

Priority summary

New Binding > Explicit Binding > Implicit Binding > Default binding

Special case – arrow function

The this in the function described above is determined at execution time. Arrow functions, on the other hand, define this at the time of definition and are not affected by the explicit binding and cannot use the new binding. Type 3. This in bar refers to this in zar.

function foo() {
    function zar() {
        const bar = () = > {
            console.log(this.a);
        }
        bar()
    }
    zar.call({a: 3})}var a = 1;
foo.call({a: 2})
Copy the code

What if we change zar to the arrow function as well? Type 2. Proof: the arrow function “this” will find the nearest “this” layer by layer.

function foo() {
    const zar = () = > {
        const bar = () = > {
            console.log(this.a);
        }
        bar()
    }
    zar.call({a: 3})}var a = 1;
foo.call({a: 2})
Copy the code

Print true for both. Since new foo() is created when the arrow function is created, this is determined. After that, even if obj uses implicit/explicit changes, this still refers to newFoo, unchanged. This example is taken from THE JS Ninja Book 2nd edition

function foo() {
    this.a = 1;
    this.getThis = () = > this;
}
const newFoo = new foo();
const obj = {
    foo: newFoo.getThis
}
console.log(obj.foo() === newFoo)
console.log(obj.foo.call({}) === newFoo)
Copy the code

Related articles

Last post js you didn’t know – About this