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
- The function is called normally;
- Functions are called as methods;
- The function is invoked forcibly using call/apply;
- 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:
- Create a brand new object.
- The new object will be connected by the implementation [[prototype]].
- The new object is bound to the function call’s this.
- 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