JavaScript Execution Mechanism (4) What does this point to?

In the previous article, we explained the principle of JavaScript’s scope chain and closure through the call stack execution context.

This time we will talk about another very important concept in JavaScript, this.

There are two main points in this article, first, what is this thing, and second, how does this point to judgment.

What is this?

The first thing we need to know is that all variables in JavaScript are actually objects, and ** objects are divided into two categories, ordinary objects, that is, Object, and the other type is function objects, that is, Function. **

The difference between these two points will be explained in detail in our next article on prototype chains.

Now we just need to know that this refers to an object, which can be a normal object or a function object.

The pointer of this changes dynamically during the execution of the code, and it ultimately points to the object that called the function.

Some people may be a little confused here: what is the relationship between scope and this?

In fact, strictly speaking, the two have nothing to do with each other:

  • Through the previous article, we can know that after the variable declaration, it is stored in the execution context. When we search for the variable by the variable name, it is through the scope chain. If we can find the location of the variable through this chain, it means that this Where is the scope of the variable included.
  • And what is this? It is also a variable in the execution context. There is a this pointer in each execution context (only function has an execution context), and this pointer points to the object that calls the current function. Of course, if you can’t point out a variable on this, you will look up along the prototype chain like an ordinary object.

So the two are basically two systems. The former is how to find a variable through the chain maintained by the execution context stack, and if it cannot be found, it will go to the upper level to find it, while ** this is different, it does not exist along the chain according to the name. Find this process, it is a pointer to the object ** that calls the function that creates the current execution context.

How to judge the direction of this

In the global execution context

First, let’s take a look at what this is in the global execution context.

You can type console.log (this) in the Console to print out the this in the global execution context, and the final output is the window object. So you can conclude that this in the global execution context points to the window object. This is also the only intersection of this and the scope chain. The bottom of the scope chain contains the window object, and this in the global execution context also points to the window object.

In the context of function execution

Now that you know that this in the global object points to the window object, let’s focus on analyzing this in the function execution context. Let’s take a look at the following code first:

1
2
3
4
5

function foo(){
console.log(this)
}
foo()

We print out the value of this inside the foo function, execute this code, and the printed object is also the window object, which means that when a function is called by default, the this in its execution context also points to the window object. You may be wondering, can you set this in the execution context to point to other objects? The answer is yes. Generally, there are three ways to set the value of this in the function execution context.

By function of

You can set the this point of the function execution context through the call method of the function. For example, in the following code, we do not directly call foo function, but call foo’s call method and use the bar object as the parameter of the call method.

1
2
3
4
5
6
7
8
9
10
11

let bar = {
myName: "Geekbang",
test1 : 1
}
function foo(){
This.myName = "Geek Time"
}
foo.call(bar)
console.log(bar)
console.log(myName)

Execute this code, and then observe the output result, you can find that this inside the foo function has pointed to the bar object, because by printing the bar object, you can see that the myName property of bar has changed from “geek state” to “geek time”, and print myName in the global execution context, the JavaScript engine prompts that the variable is undefined.

In addition to the call method, you can also use the bind and apply methods to set this in the context of function execution.

Call method settings by object

To change the this pointer in the context of function execution, in addition to the call method of function, you can also use object calls, such as the following code:

1
2
3
4
5
6
7
8

var myObj = {
Name: "Geek Time",
showThis: function(){
console.log(this)
}
}
myObj.showThis()

In this code, we define a myObj object consisting of a name property and a showThis method, and then call the showThis method through the myObj object.

Executing this code, you can see that the final output this value refers to myObj. So, you can conclude that using an object to call a method inside it, the this of the method refers to the object itself. In fact, you can also think of the JavaScript engine as converting it to myObject.showThis () when executing it

1
myObj.showThis.call(myObj)

By setting in the constructor function

1
2
3
4
function CreateObj(){
this.name = "geek time"
}
var myObj = new CreateObj()

In this code, we use new to create the object myObj, so do you know who this in the constructor function CreateObj points to?

In fact, when executing new CreateObj (), the JavaScript engine does the following four things:

  • first create an empty object tempObj;

  • then call the CreateObj.call method with tempObj as an argument to the call method, so that when the execution context of CreateObj is created, its this points to the tempObj object;

  • then execute the CreateObj function, at this time the CreateObj function execution context of this point to the tempObj object;

  • Finally returns the tempObj object.

For an intuitive understanding, we can demonstrate it with code.

1
2
3
var tempObj = {}
CreateObj.call(tempObj)
return tempObj

Note that the above process is only based on the fact that there is no return inside the’CreateObj 'function. If the function returns an object, then myObj is the object (it must return an object to change).

Special case: Arrow function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var myObj = {
Name: "Geek Time",
showThis: function(){
console.log(this)
var bar = ()=>{
this.name = "Extreme Guest State"
console.log(this)
}
bar()
}
}
myObj.showThis()
console.log(myObj.name)
console.log(window.name)

Executing this code, you will find that it also outputs the result we want, that is, the this in the arrow function bar points to the myObj object. This is because the arrow function in ES6 does not create its own execution context, so the this in the arrow function depends on its external function.