Who does this point to?
Believe that many partners have been asked this question before? Especially for beginners, the this pointing problem is a real headache. For example, if you are going to attend an interview, you will be asked to answer this question.
Before, I also felt confused about the direction of this, so I read several excellent articles about this direction, and finally I have a relatively clear understanding. Now I will summarize it.
Before I begin, I recommend that you review your scope knowledge by taking a look at my previous article: a detailed explanation of JavaScript scopes and scope chains 🔗
OK, let’s get started!
📍 Judge the basic flow of this
First of all, I give a basic process of this pointing to judgment:
1. This of a normal function
- Binding via the new operator (creates an instance object to which this in the constructor refers)
- By explicit binding(by
call
,apply
,bind
These three functions specify the binding object for this. - By implicit binding(Refers to the object last invoked, as in
obj1.obj2.foo()
Is called by,foo
Within thethis
Point to theobj2
) - The default binding(In non-strict mode
this
Points to global objects, in strict modethis
Will be bound toundefined
)
2. Arrow function this
- Points to the scope above which the function was defined
Next, we describe each of these steps in detail.
🖐 This of the ordinary function
1. Bind with new
When we call the constructor using the new operator, the following is done automatically:
- Create an empty object in the constructor
this
Point to this empty object - Inside the empty object
[[Prototype]]
Property assigned to the constructorprototype
Properties. - The constructor method is executed, and properties and methods are added to
this
Object referenced - Returns if no other object is returned from the constructor
this
Otherwise, the object returned in the constructor is returned.
The process of creating a new constructor is another frequent interview question, but it is not the main topic of this article, so I will not describe it too much. Next, let’s look at an example:
function SayHi (name) {
this.name = name
}
var Hi = new SayHi('Rocky')
console.log('Hello,', Hi.name)
Copy the code
The output is Hello, Rocky
Because var Hi = new SayHi(‘Rocky’) binds this in SayHi to the Hi object.
In addition, the result of an object created using the new operator is basically the same as that of an object created literally. Take a look at this example:
var name = 'window'
function Person (name) {
this.name = name
this.foo = function () {
console.log(this.name)
return function () {
console.log(this.name)
}
}
}
var person2 = {
name: 'person2',
foo: function() {
console.log(this.name)
return function () {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
person1.foo()()
person2.foo()()
Copy the code
First, person1.foo() prints this.name, where this must refer to person1, so it prints person1, and it returns a function called globally: Person1.foo ()(), so the output is the global name, so window. The case for person2 is the same as for person1, because foo() is called by person2 and is implicitly bound (as explained below), so this refers to person2.
So, the output is:
'person1'
'window'
'person2'
'window'
Copy the code
2. Default binding
Since explicit binding requires knowledge of default and implicit binding, the order is reversed here.
The default binding, which is used when no other binding rule can be applied, is usually a stand-alone function call.
For the default binding, just remember that in non-strict mode this refers to a global object, and in strict mode this is bound to undefined. Here’s an example:
function sayHi () {
console.log('Hello,', this.name)
}
var name = 'Rocky'
sayHi()
Copy the code
Output: Hello, Rocky
When sayHi() is called, the default binding is applied. This refers to a global object (in non-strict mode). In strict mode, this refers to undefined, and undefined has no this object, raising an error.
Since sayHi() is called in the global context, we can also call it window.sayhi (), which is equivalent to this.
The above code, if run in a browser environment, will result in Hello,Rocky
But if you run it in a Node environment, the result is Hello,undefined, because the name in node is not attached to the global object.
In this document, unless otherwise specified, the default execution result is the browser environment.
Here’s another example:
var name = "windowsName"
function fn() {
var name = 'Cherry'
innerFunction()
function innerFunction() {
console.log(this.name) // windowsName
}
}
fn()
Copy the code
The innerFunction is called as a function that is not mounted on any object, using the default binding. In non-strict mode, this refers to the window
Notice if the variable is not usedvar
Declarative, but withlet
,const
Declared, so it’s not bound towindow
Object:
let a = 10
const b = 20
function foo () {
console.log(this.a)
console.log(this.b)
}
foo()
console.log(window.a)
Copy the code
The output is
undefined
undefined
undefined
Copy the code
Implicit binding
The invocation of a function is triggered on an object, that is, a context object exists at the invocation location. The typical form is xxx.fun (). Let’s look at a piece of code:
function sayHi(){
console.log('Hello,', this.name)
}
var person = {
name: 'Rocky',
sayHi: sayHi
}
var name = 'will'
person.sayHi()
Copy the code
It prints Hello,Rocky
The sayHi function is declared externally and does not technically belong to Person, but when sayHi is called, the call location references the function using Person’s context, and the implicit binding binds this in the function call (this in this case sayHi) to the context object (Person in this case)
It is important to note that only the last layer in the object property chain affects the call location. Consider the following example:
function sayHi(){
console.log('Hello,', this.name)
}
var person2 = {
name: 'Rocky',
sayHi: sayHi
}
var person1 = {
name: 'will',
friend: person2
}
person1.friend.sayHi()
Copy the code
The result: Hello, Rocky
Because only the last layer is going to determine what this refers to, no matter how many layers there are, we’re only going to focus on the last layer in determining this, which is the friend here.
Implicit binding has a case where implicit binding loss occurs. Implicit loss is when implicitly bound functions lose bound objects under certain circumstances.
Implicit loss problems occur in two situations:
- Alias the function using another variable
- Functions passed as arguments are implicitly assigned, and callbacks lose the this binding
Next, let’s look at a concrete example:
function sayHi(){
console.log('Hello,', this.name)
}
var person = {
name: 'Rocky',
sayHi: sayHi
}
var name = 'will'
var Hi = person.sayHi
Hi()
Copy the code
The result is: Hello,will
Because Person assigns the sayHi method directly to Hi, but doesn’t call it. Since this refers to the object that last called it, and Hi is called in the global window, sayHi is called in the window. In other words, “sayHi” has nothing to do with “Person.” This refers to the window.
For this type of problem, just keep this format in mind: xxx.fn (), if there is nothing before fn(), it is definitely not implicitly bound (or implicitly bound missing). In the above code, there is no object before Hi() to call it, so it is not implicitly bound (or implicitly bound missing)
Implicit binding loss can also occur if you pass a function as an argument:
function foo () {
console.log(this.a)
}
function doFoo (fn) {
console.log(this)
fn()
}
var obj = { a: 1, foo }
var a = 2
doFoo(obj.foo)
Copy the code
The output is window 2
Here we pass obj.foo as an argument to doFoo, and as we pass this inside obj.foo() we change it to point to window. So the output a is the global a.
Here’s the catch: many people think that this in obj.foo() refers to window because it was called in doFoo, and doFoo’s this is window, but that’s not the case.
Now instead of calling doFoo from window, we’ll put it in obj2 and call it from obj2
function foo () {
console.log(this.a)
}
function doFoo (fn) {
console.log(this)
fn()
}
var obj = { a: 1, foo }
var a = 2
var obj2 = { a: 3, doFoo }
obj2.doFoo(obj.foo)
Copy the code
The result is:
{ a:3, doFoo: f }
2
Copy the code
Now call obj2.dofoo (), where this should refer to obj2, since obj2 called it.
But obj.foo() still prints a 2, which is a under window.
For this question, just remember the following conclusion:
Implicit loss also occurs when a function is passed as an argument to another function, regardless of the reference to this of the enclosing function (such as this of doFoo() above). In non-strict mode, the function’s this is bound to the window; in strict mode, it is bound to undefined.
Here’s a different example:
function foo() {
setTimeout(function () {
console.log('id:', this.id)
}, 100);
}
var id = 21
foo() // 21
Copy the code
In the above example, function () {console.log(‘id:’, this.id)} the anonymous function is passed to setTimeout as an argument, so implicit binding loss occurs, so this should refer to the global object window, So the output is the global variable ID. We can also remember that the this of an anonymous function always refers to the window
Let’s look at a little more comprehensive example:
function sayHi(){
console.log('Hello,', this.name)
}
var person1 = {
name: 'Rocky',
sayHi: function(){
setTimeout(function(){
console.log('Hello',this.name)
})
}
}
var person2 = {
name: 'will',
sayHi: sayHi
}
var name='skumion'
person1.sayHi()
setTimeout(person2.sayHi,100)
setTimeout(function(){
person2.sayHi()
},200)
Copy the code
The result is:
Hello, skumion
Hello, skumion
Hello, will
Copy the code
-
The first output, which is easy to understand, is the case of implicit binding loss, where this holds the pointer to the window.
-
SetTimeout (fn,delay) {fn()} is equivalent to assigning person2.sayHi to a variable fn and finally executing the variable, at which point this in sayHi has no relation to person2.
-
SayHi () uses an implicit binding, so this refers to person2 and has nothing to do with the current scope.
4. Explicit binding
An explicit binding is an explicit call,apply,bind that specifies the object to which this refers.
The first argument to call,apply, and bind is the object to which the corresponding function’s this points. Call and apply work in the same way, but in different ways. The call() method takes a list of arguments, while the apply() method takes an array of arguments.
- Syntax for call:
function.call(thisArg, arg1, arg2, ...)
- The syntax of apply:
function.apply(thisArg , [ argsArray])
- Bind syntax:
function.bind(thisArg, arg1, arg2, ...)
Unlike call() and apply(), bind() creates a new function that must be called manually before it can be executed.
var name = 'Rocky', age = 23 var obj = { name: 'will', objAge: this.age, myFun: Function () {console.log(this.name + 'age' + this.age)}} var anotherObj = {name: 'skumion', age: 18}Copy the code
The output is as follows
Obj. myfun. call(anotherObj)// Skumion age 18 obj. myfun. apply(anotherObj) // Skumion age 18 Obj.myfun.bind (anotherObj)() // skumion age 18Copy the code
Let’s do another example
function sayHi(){ console.log('Hello,', this.name) } var person = { name: 'Rocky', sayHi: SayHi} var name = 'will' var Hi = person. SayHi Hi. Call (person)Copy the code
The output is Hello, Rocky
Because this is explicitly bound to Person using an explicit binding.
What happens if you bind this to null or undefined via call, apply, or bind?
var foo = {
name: 'will'
}
var name = 'Rocky'
function bar() {
console.log(this.name)
}
bar.call(null); //Rocky
Copy the code
As you can see from the above example, binding this to null or undefined is ignored and the default binding rule is applied.
In addition, with explicit binding, the same binding loss that occurs with implicit binding can occur.
function sayHi(){
console.log('Hello,', this.name)
}
var person = {
name: 'Rocky',
sayHi: sayHi
}
var name = 'will'
var Hi = function(fn) {
fn()
}
Hi.call(person, person.sayHi)
Copy the code
The output is Hello, will
The reason is simple: Hi. Call (person, Person.sayhi) does refer this to person. When fn is executed, however, the sayHi method is called directly (remember: person.sayHi has been assigned to FN, and the implicit binding is missing) without specifying the value of this, which is the default binding.
What if we want the binding not to be lost? Very simply, when fn is called, it is explicitly bound.
function sayHi(){
console.log('Hello,', this.name)
}
var person = {
name: 'Rocky',
sayHi: sayHi
}
var name = 'will'
var Hi = function(fn) {
fn.call(this)
}
Hi.call(person, person.sayHi)
Copy the code
At this point, the output is Hello, Rocky
Since person is bound to this in the Hi function, fn uses call(this) to bind the object to sayHi’s function. In this case, the “sayHi” refers to the Person object.
OK, here’s another example:
var obj1 = {
a: 1
}
var obj2 = {
a: 2,
foo1: function () {
console.log(this.a)
},
foo2: function () {
setTimeout(function () {
console.log(this)
console.log(this.a)
}.call(obj1), 0)
}
}
var a = 3
obj2.foo1()
obj2.foo2()
Copy the code
The result is:
2
{ a: 1 }
1
Copy the code
I believe this problem is not difficult at all for you now, but I use this example to introduce a detail question:
Since call can change the direction of this, can I write it this way? obj2.foo2.call(obj1)
Note: This is wrong! If this is the case, the value of this in foo2 will change, but we know that the value of this in foo2 is irrelevant to the value of this in setTimeout, because the timer is always called by the window.
Here’s another detail that’s easy to overlook:
function foo () {
console.log(this.a)
}
var obj = { a: 1 }
var a = 2
foo()
foo.call(obj)
foo().call(obj)
Copy the code
foo()
It will print normallywindow
Under thea
, that is,2
foo.call(obj)
Because it’s explicitly boundthis
So it prints outobj
Under thea
, that is,1
foo().call(obj)
The beginning will executefoo()
Function, print out2
But it will be rightfoo()
The return value of the function is executed.call(obj)
Operation, but we can seefoo()
The return value of the function isundefined
, so an error will be reported.
The output is:
2
1
2
Uncaught TypeError: Cannot read property 'call' of undefined
Copy the code
So we can see thatfoo.call()
andfoo().call()
One is for the function, the other is for the return value of the function.
Return (); return (); return ();
function foo () {
console.log(this.a)
return function () {
console.log(this.a)
}
}
var obj = { a: 1 }
var a = 2
foo()
foo.call(obj)
foo().call(obj)
Copy the code
- The first number
2
Nature isfoo()
Output, thoughfoo()
The function also returns an anonymous function, but does not call it, just writes itfoo()()
, so that it is called anonymous function. - Second number
1
isfoo.call(obj)
Output due to.call()
Is followed byfoo
So what’s changed isfoo()
Within thethis
Point to, and.call()
Is going to make the functionExecuted immediatelySo print out1
Similarly, it does not call the returned function. - Number three
2
isfoo().call(obj)
To perform firstfoo()
It was printed out at this timefoo()
Within thethis
Or towindow
. - The execution of the
foo()
After that, an anonymous function is returned and used later.call(obj)
To change this anonymous functionthis
It points to it and calls it, so it prints1
.
The output is:
2
1
2
1
Copy the code
5. Priority
At this point, we have introduced the four binding rules for this. If more than one rule is applied at the same time, the priority of the four binding rules is:
New Binding > Explicit Binding > Implicit Binding > Default binding
🖖 arrow function this
There are a few things to note about the arrow function:
- Arrow functions don’t have their own
this
Object (see below), so you can’t use call(), apply(), or bind() to change the direction of this. - Should not be used as constructors, that is, on arrow functions
new
Command, otherwise an error will be thrown. - Unusable
arguments
Object that does not exist in the function body. If you do, use the REST argument instead. - Unusable
yield
Command, so arrow functions cannot be used as Generator functions.
Of the four points above, the most important is the first. For normal functions, the inner this refers to the object on which the function is running, but this is not true for arrow functions. It does not have its own this object; the internal this is the this in the upper scope of the definition. That is, the this pointer inside the arrow function is fixed, in contrast to the mutable this pointer in normal functions.
1
Function foo() {setTimeout(() => {console.log('id:', this.id)}, 100); } var id = 21 foo.call({ id: 42 }) // id: 42Copy the code
In the code above, the argument to setTimeout() is an arrow function that takes effect when foo is generated and will not execute until 100 milliseconds later. If it were a normal function, this would point to the global object Window and print 21. However, the arrow function causes this to always point to the object where the function definition is in effect ({id: 42} in this case), so it prints 42.
In the following example, the callback function is an arrow function and a normal function, compared to their internal this reference.
Function Timer() {this.s1 = 0 this.s2 = 0 SetInterval (function () {this.s2++}, 1000)} var timer = new timer () setTimeout(() => console.log('s1: ', timer.s1), 3100) setTimeout(() => console.log('s2: ', timer.s2), 3100) // s1: 3 // s2: 0Copy the code
In the above code, two timers are set inside the Timer function, using the arrow function and the normal function. The former has the scope in which the this binding is defined (the Timer function), and the latter has the scope in which the runtime is defined (the global object). So, after 3100 milliseconds, timer.s1 is updated 3 times, and timer.s2 is not updated once.
The arrow function can actually make this point immutable, and binding this makes it immutable, which is a great feature for wrapping callback functions. Here is an example where the DOM event callback function is wrapped in an object.
var handler = {
id: '123456',
init: function() {
document.addEventListener('click',
event => this.doSomething(event.type), false)
},
doSomething: function(type) {
console.log('Handling ' + type + ' for ' + this.id)
}
}
Copy the code
The above code uses the arrow function in its init() method, which causes the arrow function this to always point to a handler object. If the callback is a normal function, running this.dosomething () will result in an error because this points to the window object (this of an anonymous function points to window).
Here is the ES5 code generated by the Babel arrow function, which makes it clear what this points to.
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id)
}, 100);
}
// ES5
function foo() {
var _this = this
setTimeout(function () {
console.log('id:', _this.id)
}, 100)
}
Copy the code
In the code above, the converted VERSION of ES5 makes it clear that the arrow function does not have its own this at all, but instead refers to the outer this.
In addition, since the arrow function does not have its own this, it cannot of course use call(), apply(), or bind() to change the direction of this.
(function() {
return [
(() => this.x).bind({ x: 'inner' })()
]
}).call({ x: 'outer' })
// ['outer']
Copy the code
In the above code, the arrow function does not have its own this, so the bind method is invalid. The inner this points to the outer this.
2. Not applicable
Since the arrow function causes this to change from “dynamic” to “static”, there are four situations where arrow functions should not be used.
The first case is to define a method of an object that includes this inside.
const cat = {
lives: 9,
jumps: () => {
this.lives--
}
}
Copy the code
In the code above, the cat.jumps() method is an arrow function, which is incorrect. 4. When calling cat.jumps(), the this inside the method points to cat if it is a normal function. If you write an arrow function like the one above, such that this points to a global object, you will not get the expected result. This is because the object does not constitute a separate scope, resulting in the scope of the jump arrow function being defined as global.
globalThis.s = 21;
const obj = {
s: 42,
m: () => console.log(this.s)
};
obj.m() // 21
Copy the code
In the example above, obj.m() is defined using the arrow function. The JavaScript engine does this by generating the arrow function in the global space and assigning it to obj.m. This causes this inside the arrow function to point to the global object, so obj.m() prints 21 in the global space instead of 42 inside the object. The code above is actually equivalent to the code below.
globalThis.s = 21;
globalThis.m = () => console.log(this.s);
const obj = {
s: 42,
m: globalThis.m
};
obj.m() // 21
Copy the code
For this reason, it is recommended that the attributes of an object be defined in the traditional way rather than using arrow functions.
The second case is when dynamic this is required, and arrow functions should also not be used.
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
Copy the code
When the code above runs, clicking on the button will cause an error because button’s listener is an arrow function, resulting in this being the global object. If changed to a normal function, this dynamically points to the button object being clicked.
The third case is when defining prototype methods, arrow functions should also not be used
function Foo (value) {
this.value = value
}
Foo.prototype.getValue = () => console.log(this.value)
const foo1 = new Foo(1)
foo1.getValue() // undefined
Copy the code
The fourth case is that constructors should also not use arrow functions
const Foo = (value) => { this.value = value; } const foo1 = new Foo(1) Uncaught TypeError: Foo is not a constructor console.log(foo1)Copy the code
3. This in Vue
All functions managed by Vue are best written as normal functions, so that this refers to the VM or component instance object. Such as:
computed: {
foo () {
console(this) // vm
}
},
methods: {
bar () {
console(this) // vm
}
}
Copy the code
All functions not managed by Vue (timer callbacks, Ajax callbacks, Promise callbacks, etc.) are best written as arrow functions so that this points to the VM or component instance object. Such as:
methods: {
foo () {
setTimeOut (() => {
console.log(this) // vm
}, 1000)
},
bar () {
return new Promise ((resolve, reject) => {
resolve()
console.log(this) // vm
})
}
}
Copy the code
📒 exercises
The first question
"use strict"
var a = 10
function foo () {
console.log('this1', this)
console.log(window.a)
console.log(this.a)
}
console.log(window.foo)
console.log('this2', this)
foo()
Copy the code
- Turns on strict mode, just to say that it doesWithin the functionthe
this
Point to theundefined
It doesn’t change the globalthis
Pointing to. sothis1
Is printed inundefined
And thethis2
orwindow
Object. - Plus, it doesn’t stop it
a
Is bound to thewindow
On the object.
The output is:
f foo() {... } 'this2' Window{... } 'this1' undefined 10 Uncaught TypeError: Cannot read property 'a' of undefinedCopy the code
The second question
var name = "windowsName"
var a = {
name : "Rocky",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100)
}
};
a.func2()
Copy the code
The anonymous function function () {this.func1()} is passed to setTimeout as an argument, and implicit binding loss occurs, so this refers to the global window object, but func1 is not present in the window.
Func1 is not a function
The third question
function foo () {
console.log(this.a)
return function () {
console.log(this.a)
}
}
var obj = { a: 1 }
var a = 2
foo.call(obj)()
Copy the code
First foo.call(obj) prints the 1 in obj, and then foo returns an anonymous function. This in foo() is specified as obj, but the last call to the anonymous function is window. Because foo.call(obj)() is called globally.
The output is:
1
2
Copy the code
The fourth question
function foo () {
console.log(this.a)
}
var obj = { a: 1, foo };
var a = 2
var foo2 = obj.foo
var obj2 = { a: 3, foo2: obj.foo }
obj.foo()
foo2()
obj2.foo2()
Copy the code
In obj.foo(), foo is called by obj, so this in foo refers to obj, printing 1
Var foo2 = obj.foo is a case of implicit binding loss, so foo2() calls foo() directly on window, so output 2
Var obj2 = {a: 3, foo2: obj. Foo} is also an implicit lost binding case, obj. Foo is assigned to foo2 directly, and foo2 is called by obj2, so output 3
So the output is:
1
2
3
Copy the code
The fifth problem
How many references to this in the following code?
function foo() {
return () => {
return () => {
return () => {
console.log('id:', this.id)
}
}
}
}
var f = foo.call({id: 1})
var t1 = f.call({id: 2})()()
var t2 = f().call({id: 3})()
var t3 = f()().call({id: 4})
Copy the code
The answer is that this refers to only one function, foo’s this, and outputs three ids: 1. This is because all inner functions are arrow functions and do not have their own this. Their this is actually the this of the outermost foo function. So no matter how nested, T1, T2, and T3 all output the same result. If all the inner functions in this example are written as normal functions, then each function’s this points to a different object of the runtime.
The output is:
id: 1
id: 1
id: 1
Copy the code
The sixth question
var name = 'window'
function Person (name) {
this.name = name
this.foo = function () {
console.log(this.name)
return function () {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo.call(person2)()
person1.foo().call(person2)
Copy the code
This is a new binding combined with explicit binding, detailed analysis as follows
person1.foo.call(person2)()
willfoo()
Within the functionthis
Points to theperson2
So print it outperson2
, while the internally returned anonymous function is created bywindow
Call, so print outwindow
.person1.foo().call(person2)
Is to anonymize the functionthis
Explicitly bound toperson2
Up, so it’s going to print outperson2
.
The following output is displayed:
'person2'
'window'
'person1'
'person2'
Copy the code
Number 7
var obj = {
a: 1,
foo: function (b) {
b = b || this.a
return function (c) {
console.log(this.a + b + c)
}
}
}
var a = 2
var obj2 = { a: 3 }
obj.foo(a).call(obj2, 1)
obj.foo.call(obj2)(1)
Copy the code
- Began to call
obj.foo(a)
will2
The incomingfoo
Function and assign to the type parameterb
And, because of closures, is accessible within anonymous functionsb
Is used later when calling anonymous functionscall()
Changed thethis
Pointer to make anonymous function insidethis.a
for3
And pass in the last argument1
, so the first line should output3 plus 2 plus 1
, that is,6
. - And the second row,
obj.foo.call(obj2)
Here is thefoo
Within the functionthis
Points to theobj2
And no arguments are passed, sob
First theundefined
But because of one sentenceb = b || this.a
,b
Into the3
; And the last piece of code(1)
, is calling an anonymous function, and this anonymous functionthis
It should be pointing towindow
, so the output is2 plus 3 plus 1
for6
.
The output is:
6
6
Copy the code
The eighth problem
const obj = {
aaa() {
setTimeout(function() { // 1.普通函数的setTimeout
setTimeout(function() {
console.log(this)
})
setTimeout(() => {
console.log(this)
})
})
setTimeout(() => { // 2.箭头函数的setTimeout
setTimeout(function(){
console.log(this)
})
setTimeout(() => {
console.log(this)
})
})
}
}
obj.aaa()
Copy the code
The first normal function setTimeout: this points to the window
- Ordinary functional
The child setTimeout
: Default binding, this refers to the global objectwindow
- Arrow function
The child setTimeout
: refers to this of the upper scope, and this of the upper scope iswindow
SetTimeout of the second arrow function: Look for this in the upper scope AAA, because AAA is called by obj, and this of the AAA method points to obj, so this points to obj
- Ordinary functional
The child setTimeout
: Default binding, this refers to the global objectwindow
- Arrow function
The child setTimeout
: refers to this of the upper scope, and this of the upper scope isobj
So the final output is:
window
window
window
obj
Copy the code
Question 9
var name = 'window'
var obj1 = {
name: 'obj1',
foo1: function () {
console.log(this.name)
return () => {
console.log(this.name)
}
},
foo2: () => {
console.log(this.name)
return function () {
console.log(this.name)
}
}
}
var obj2 = {
name: 'obj2'
}
obj1.foo1.call(obj2)()
obj1.foo1().call(obj2)
obj1.foo2.call(obj2)()
obj1.foo2().call(obj2)
Copy the code
The arrow function this cannot be changed directly by bind, call, or apply, but can be changed indirectly by changing the direction of this in the scope. Next, let’s analyze it in detail:
obj1.foo1.call(obj2)()
The first layer is a normal function and passes.call
Changed thethis
Pointing toobj2
So it prints outobj2
The second layer is the arrow functionthis
And in the outer scopethis
Same, thereforeobj2
.obj1.foo().call(obj2)
Print out the first layerobj1
The second layer is the arrow function used.call
Want to changethis
But it didn’t succeed, so.call(obj2)
It doesn’t work for the arrow function, so print it outobj1
.obj1.foo2.call(obj2)()
The first layer is the arrow function, and it wants to pass through.call(obj2)
changethis
Pointer to, but invalid, and its outer scope iswindow
So it prints outwindow
, the second layer is ordinary function,this
Is the last callerwindow
, so it will also print outwindow
.obj1.foo2().call(obj2)
The first layer is the arrow function, and the outer scope iswindow
To print outwindow
The second layer is a normal function and is used.call(obj2)
To change thethis
Point to, so it prints outobj2
.
The following output is displayed:
'obj2' 'obj2'
'obj1' 'obj1'
'window' 'window'
'window' 'obj2'
Copy the code
The first ten questions
var obj = { hi: function(){ console.log(this) return ()=>{ console.log(this) } }, sayHi: function(){ return function() { console.log(this) return ()=>{ console.log(this) } } }, say: ()=>{ console.log(this) } } let hi = obj.hi() // 1 hi() // 2 let sayHi = obj.sayHi() let fun1 = sayHi() // 3 fun1() // 4 obj.say() // 5Copy the code
obj.hi()
Corresponding to the implicit binding rule for this, this is bound toobj
Up, so outputobj
.hi()
So what we’re doing here is executing the arrow function, and the arrow function is going to go up the scope and look for this, and we just figured out that this isobj
, so outputobj
sayHi()
Is the case of implicit binding loss, in which this performs the default binding and this points to a global objectwindow
fun1()
So what we’re doing here is we’re doing the arrow function, and the arrow function is going to go up one level and look for this, which points towindow
, so the output iswindow
obj.say()
I’m doing the arrow function, so there’s no this in the current block obj, so I’m just going to look up, and I’m going to find the global this, which points towindow
The output from 1-5 is as follows:
obj
obj
window
window
window
Copy the code
OK, that’s all for this article!
If you see this, thank you for taking the time to read my article. If there is anything inappropriate in my article, please feel free to comment and give me a “like” if you think it is helpful.
reference
Hi, do you really understand this? This, call, apply, bind 【 suggest 👍】
The articles
Do you really understand script tags? JavaScript scope and scope chains 🔗 Thoroughly understand scope, execution context, lexical environment 🔎 mock. js mocks back-end interface data ✨