原文 : What is “this” in JavaScript?
If you’ve done any development with JavaScript libraries, you’ve probably noticed a particular keyword named this. Although this is very common in JavaScript, fully understanding how the this keyword works and how it is used in code is a challenge for quite a few developers. In this article, I’ll give you a deeper understanding of this and how it works.
Before you begin, make sure Node is installed. Then, open the command line terminal and run the Node command.
“This” in the global environment
It’s not easy to understand how this works. We understand how this works by placing this in different contexts. First take a look at the global environment.
In a global context, this corresponds to the global object global.
> this === global
true
Copy the code
But this only works in Node. If we run the same code in a JS file, the output is false.
If you want to test the effect, you can create a file called index.js that contains the following code:
console.log(this === global);
Copy the code
Then run the file using the node command:
$ node index.js
false
Copy the code
The reason is that in JavaScript files, this is equivalent to module.exports, not global.
“This” in the function
The this value in a function is usually defined by the caller of the function. Therefore, each time the function is executed, the value of this inside the function may be different.
In the index.js file, write a very simple function that checks if this is equal to the global object.
function rajat() {
console.log(this === global)
}
rajat()
Copy the code
If we run this code using Node, the output is true. If you add “use strict” to the top of the file and run it again, you will get false output because this is now undefined.
To further illustrate this, let’s create a simple function that defines the real name of the superhero and the hero’s name.
function Hero(heroName, realName) {
this.realName = realName;
this.heroName = heroName;
}
const superman= Hero("Superman"."Clark Kent");
console.log(superman);
Copy the code
Note that this function is not written in strict mode. Node running this code doesn’t get Superman and Clark Kent as we expect, but it just gives us a undefined.
The reason behind this is that since the function is not written in strict mode, this points to the global object.
If we run this code in strict mode, we get an error because JavaScript does not allow assigning the properties realName and heroName to undefined. This is actually a good thing, because it prevents us from creating global variables.
Also, writing the function name in uppercase means that we need to treat it as a constructor and call it using the new operator. Replace the last two lines of the above code snippet with the following:
const superman = new Hero("Superman"."Clark Kent");
console.log(superman);
Copy the code
Run the node index.js command again and you should now get the output you expect.
“This” in the constructor
JavaScript has no specific constructor. All we can do is convert a function call to a constructor call using the new operator, as shown in the previous section.
When the constructor is called, a new object is created and set to the function’s this argument. The constructor implicitly returns this object unless we explicitly return another object.
Add the following return statement inside the hero function:
return {
heroName: "Batman".realName: "Bruce Wayne"};Copy the code
If we run the Node command again, we see that the return statement above overrides the constructor call.
The only case where a return statement does not override a constructor call is if the return statement does not return an object. In this case, the object will contain the original value.
“This” in the method
When a function is called as a method of an object, this refers to that object, also known as the receiver of the function call.
If the Hero object has a dialogue method, the this value in dialogue points to the Hero itself. The hero at this point is also called the receiver of the dialogue method call.
const hero = {
heroName: "Batman",
dialogue() {
console.log(`I am The ${this.heroName}! `); }}; hero.dialogue();Copy the code
This example is very simple, but in the real world, our approach makes it difficult to track the receiver. Add the following code snippet to the end of index.js.
const saying = hero.dialogue;
saying();
Copy the code
If I store a reference to dialogue in another variable and call that variable as a function. Node runs the code, and this returns undefined because the method has lost the sink. This points to global, not hero.
When we pass one method as a callback to another, we typically lose the sink. We can solve this problem by adding a wrapper function or using the bind method to bind this to a specific object.
Call () and the apply ()
Although the function’s this value is set implicitly, we can also explicitly set this when calling the function using call() and apply().
Let’s refactor the code snippet from the previous section as follows:
function dialogue () {
console.log (`I am The ${this.heroName}`);
}
const hero = {
heroName: 'Batman'};Copy the code
If we want to use the Hero object as a receiver for the dialogue function, we can use call() or apply() like this:
dialogue.call(hero)
// or
dialogue.apply(hero)
Copy the code
If you are using Call or apply in non-strict mode, the JavaScript engine ignores null or undefined passed to call or apply. This is one of the reasons why it is recommended to always write code in strict mode.
bind()
When we pass a method as a callback to another function, there is always the risk of losing the method’s original receiver, making this point to the global object.
The bind() method binds this to a value. In the code snippet below, bind creates a new dialogue function and sets this to hero. (Translator’s Note: The bind() method creates a new function called -bound function-bf. When called, the bind function takes as this the first argument passed to the bind() method when it was created. The second and subsequent arguments passed to the bind() method are called as arguments to the original function, along with arguments from the bind function’s runtime itself, in that order.
const hero = {
heroName: "Batman",
dialogue() {
console.log(`I am The ${this.heroName}`); }}; setTimeOut(hero.dialogue.bind(hero),1000);
Copy the code
In this case, you cannot change the value of this even if you use the Call or apply methods.
“This” in the arrow function
The this inside the arrow function is quite different from other types of JavaScript functions. An arrow function uses the this value from its enclosing execution context, since it does have one of its own.
The arrow function permanently captures this value, preventing Apply or Call from changing it later.
To explain how this works in the arrow function, let’s write an arrow function:
const batman = this;
const bruce = (a)= > {
console.log(this === batman);
};
bruce();
Copy the code
Here, we store the this value in a variable and compare it to the this value inside the arrow function. Run Node index.js on a terminal and the output should be true.
The this value in the arrow function cannot be set explicitly. In addition, if you use methods like call, apply, or bind to pass values to this, the arrow function ignores them. The arrow function refers to the this value that the arrow function set when it was created. If the arrow function is wrapped by a non-arrow function, the value of this is determined by the nearest non-arrow function, otherwise it is undefined.
Arrow functions cannot also be used as constructors. Therefore, we cannot attribute this within the arrow function either.
So what can the arrow function do with this?
The arrow function gives us access to this in the callback function. To see how this works, use the following counter object:
const counter = {
count: 0,
increase() {
setInterval(function() {
console.log(++this.count);
}, 1000);
}
}
counter.increase();
Copy the code
Running this code with Node index.js yields only a list of nans. This is because this.count no longer points to the counter object. It actually points to the global object.
If you want the counter to work, you can override it using the arrow function.
const counter = {
count: 0,
increase () {
setInterval ((a)= > {
console.log (++this.count);
}, 1000); }}; counter.increase();Copy the code
The callback uses this to bind to the increase method, and counter now works fine.
Note: Do not write ++this.count as this.count + 1. The latter increments the value of count only once, returning the same value each iteration.
“This” in the Class
Classes are the most important part of a JavaScript application. Let’s look at how this is different in the class.
Classes usually contain a constructor, which can point to any newly created object.
However, when used as a method, this can point to any other value if the method is called as a normal function. Like methods, classes can lose track of receivers.
Let’s transform the Hero function we created earlier into a class. This class contains a constructor and a dialogue() method. Finally, create an instance of the class and call the Dialogue method.
class Hero {
constructor(heroName) {
this.heroName = heroName;
}
dialogue() {
console.log(`I am The ${this.heroName}`)}}const batman = new Hero("Batman");
batman.dialogue();
Copy the code
The this in the constructor points to the newly created class instance. When we call batman.dialogue(), dialogue() is called as a method, and batman is its receiver.
But if we store a reference to the Dialogue () method and call it later as a function, we lose the receiver for that method, where this points to undefined.
const say = batman.dialogue;
say();
Copy the code
The error occurs because JavaScript classes implicitly run in strict mode. We called the say() function without any automatic binding. To fix this, we need to manually bind the dialogue() function to batman using bind().
const say = batman.dialogue.bind(batman);
say();
Copy the code
We can also do this binding in the constructor method.
conclusion
We need to use this in JavaScript just like we need pronouns in English. Take these two sentences:
- Rajat loves DC Comics.
- Rajat also loves Marvel movies.
We can use pronouns to put these two sentences together, so they now become:
Rajat loves DC Comics, and he also loves Marvel Comics
This short syntax lesson perfectly illustrates the importance of this in JavaScript. Just as the pronoun he links two sentences together, this can serve as a shortcut to quoting the same thing again.
Hopefully, this article has helped you answer JavaScript questions about this and navigate this simple but very important keyword.
IVWEB Technology Weekly shocked online, pay attention to the public number: IVWEB community, weekly timing push quality articles.
- Collection of weekly articles: weekly
- Team open source project: Feflow