The ‘this’ keyword is a simple concept but can be sometimes tricky to understand by developers who are new to the Javascript environment. Mostly because in JS, the behaviour of this is slightly different than other programming languages (such as Java, for example).
So what’s this?
To put simply, this is a reference to an object. Which object you may ask? Well that depends on the context of the code this is used in. The context depends on the scope where the code was invoked.
Outside functions
If you use this outside of functions, i.e., in the Global Context, this will point to the global object, i.e., the window object. Recall that the window object allows the JS engine to interact with browser’s capabilities and functions. Let’s understand this through examples:
// displays the alert message in the browser
// works the same as window.alert() or just alert()
this.alert("This should alert out message in the browser");
// waits for 2 secs, then prints the message on the console
// works the same as window.setTimeout() or just setTimeout()
this.setTimeout(() => {
// works the same as window.console.log() or just console.log(). You get the pattern now :)
this.console.log("Hello from the browser");
}, 2000);
var helloObj = "Hello JS"; // declare variable in the global context
console.log(this.helloObj); // prints 'Hello JS' in the console
Within functions
Behaviour of this within functions is same as outside functions, i.e, this will still point to the global object. This is because the function is being called without the context of an object:
var greet = {
message: "Hello!",
};
function fun() {
console.log(this.greet.message);
}
fun(); // 'Hello'
Within methods
Understanding the context of this becomes slightly trickier when used inside methods. Remember - the value of this depends on how the method was invoked and NOT on where the method was defined. For example,
var obj = {
message: "Hello!",
printThis: function () {
console.log(this); // 'this' points to object 'obj'
},
};
obj.printThis();
But if we assign the method printThis of obj to another variable, we are executing the method in the global context. Hence this would be assigned to window.
var printThisGlobal = obj.printThis;
printThisGlobal(); // 'this' points to object 'window'
Note how the value of this is dependent on how these functions are invoked.
Important - Inner functions within methods will have global scope since the function would be called without the object’s context:
var data = "Global scope!";
var obj = {
data: "obj scope!",
showData() {
setTimeout(function () {
console.log(this.data); // prints 'Global Scope!'
}, 2000);
},
};
obj.showData();
But what if we want the inner functions to retain the object’s context? Well there are two popular ways to achieve this:
Method 1 - Store the context in another variable:
var data = "Global scope!";
var obj = {
data: "obj scope!",
showData() {
var that = this; // storing the context in the that variable
setTimeout(function () {
console.log(that.data); // prints 'obj scope!'
}, 2000);
},
};
obj.showData();
Method 2 (My favourite) - Arrow functions:
Arrow functions take the context from the enclosing function, hence are cleaner if we want the function to retain the context of this:
var data = "Global scope!";
var obj = {
data: "obj scope!",
showData() {
setTimeout(() => {
console.log(this.data); // prints 'obj scope!'
});
},
};
obj.showData();
Within constructor functions
When using this within constructor functions (functions created using the new keyword), this points to the newly created object:
function Rectangle(height, width) {
this.height = height; // this points to the 'Rectangle' object created using the new keyword
this.width = width;
}
let rectangle1 = new Rectangle(5, 10);
console.log(rectangle1);
Remember to use the new keyword when using constructor functions to avoid setting variables within the function in the global context and subsequently end up polluting it.
Within classes
When used within ES6 classes, this keyword points to the current object created using the new word (this behaviour is similar to constructor functions). Only catch is that since strict mode is enabled by default when using classes, this would point to undefined for functions defined under non-static methods.
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
getArea() {
return this.height * this.width;
}
showHeight() {
setTimeout(function () {
console.log(this.height); // undefined
});
}
}
const rectangle = new Rectangle(5, 10);
console.log(rectangle.getArea()); // 50
rectangle.showHeight();
Conclusion
I hope this gives you a fair understanding of how this works in Javascript. Since this is important to understand other concepts in JS, it is extremely imperative that you understand it well.
The strict mode significantly impacts how this behaves, so be sure to check it out.
There are methods which allow you to explicitly set the value of this within objects. These are namely call, apply & bind. You can read more about these methods by clicking on the inline links. I will try to cover more on these methods in a separate article.
If there is something you feel I have missed in this article, do let me know in the comments section below.
References
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
Top comments (0)