The Final Steps to Mastering JavaScript’s “this” Keyword

Share this article

In a previous article we learned the fundamentals of using JavaScript’s this keyword properly. We saw that the crucial factor in determining what this refers to, is to find out the current execution context. However, this task can be a bit tricky in situations where the context gets changed in a way we don’t expect. In this article I will highlight when this might happen and what we can do to remedy it.

Fixing Common Issues

In this section we’ll explore some of the most common issues arising from the use of the this keyword and we’ll learn how to fix them.

1. Using this in Extracted Methods

One of the most common mistakes that people make is when trying to assign an object’s method to a variable and expecting that this will still point to the original object. As we can see from the following example, that simply doesn’t work.
var car = {
brand: "Nissan",
getBrand: function(){
console.log(this.brand);
}
};

var getCarBrand = car.getBrand;

getCarBrand(); // output: undefined
JS Bin Even though getCarBrand appears to be a reference to car.getBrand(), in fact, it’s just another reference to getBrand() itself. We already know that the call-site is what matters in determining the context, and here, the call-site is getCarBrand(), which is a plain and simple function call. To prove that getCarBrand points to a baseless function (one which isn’t bound to any specific object), just add alert(getCarBrand); to the bottom of the code and you’ll see the following output:
function(){
console.log(this.brand);
}
getCarBrand holds just a plain function, which is no longer a method of the car object. So, in this case, this.brand actually translates to window.brand, which is, of course, undefined. If we extract a method from an object, it becomes a plain function again. Its connection to the object is severed, and it no longer works as intended. In other words, an extracted function is not bound to the object it was taken from. So how can we remedy this? Well, if we want to keep the reference to the original object, we need to explicitly bind the getBrand() function to the car object when we assign it to the getCarBrand variable. We can do this by using the bind() method.
var getCarBrand = car.getBrand.bind(car);
getCarBrand(); // output: Nissan
Now, we get the proper output, because we successfully redefine the context to what we want it to be.

2 this Used in Callbacks

The next issue occurs when we pass a method (that uses this as a parameter) to be used as a callback function. For example:
<button id="btn" type="button">Get the car's brand</button>

var car = {
brand: "Nissan",
getBrand: function(){
console.log(this.brand);
}
};

var el = document.getElementById("btn");
el.addEventListener("click", car.getBrand);
JS Bin Even though we use car.getBrand, we actually only get the function getBrand() which is attached to the button object. Passing a parameter to a function is an implicit assignment, so what happens here is almost the same as in the previous example. The difference is that now car.getBrand
is not explicitly assigned, but implicitly. And the result is pretty much the same—what we get is a plain function, bound to the button object. In other words, when we execute a method on an object, which is different from the object upon which the method was originally defined, the this keyword no longer refers to the original object, rather to the object that invokes the method. With reference to our example: we are executing car.getBrand on el (the button element), not the car object, upon which it was originally defined. Consequently, this no longer refers to car, rather to el. If we want to keep the reference to the original object intact, again, we need to explicitly bind the getBrand() function to the car object by using the bind() method.
el.addEventListener("click", car.getBrand.bind(car));
Now, everything works as expected.

3 this Used Inside Closures

Another instance when this‘s context can be mistaken is when we use this inside of a closure. Consider the following example:
var car = {
brand: "Nissan",
getBrand: function(){
var closure = function(){
console.log(this.brand);
};
return closure();
}
};

car.getBrand(); // output: undefined
JS Bin Here, the output we get is undefined, because closure functions (inner functions) don’t have access to the this variable of outer functions. The net result is that this.brand is equal to window.brand, because this in inner functions is bound to the global object. To fix this issue, we need to keep this bound to the getBrand() function.
var car = {
brand: "Nissan",
getBrand: function(){
var closure = function(){
console.log(this.brand);
}.bind(this);
return closure();
}
};

car.getBrand(); // output: Nissan
JS Bin This binding is equivalent to car.getBrand.bind(car). Another popular method to fix closures, is to assign the this value to another variable, thus preventing the unwanted change.
var car = {
brand: "Nissan",
getBrand: function(){
var self = this;
var closure = function(){
console.log(self.brand);
};
return closure();
}
};

car.getBrand(); // output: Nissan
JS Bin
Here, the value of this can be assigned to _this, that, self, me, my, context, an object’s pseudo name, or whatever else works for you. The main point is to keep a reference to the original object.

ECMAScript 6 to the Rescue

In the previous example we saw a primer on what is known as “lexical this“—when we set the this value to another variable. In ECMAScript 6 we can use the similar, but more elegant, technique, applicable via the new arrow functions. Arrow-functions are created not by the function keyword, but by the so-called “fat arrow” operator (=>). Unlike regular functions, arrow functions take the this value from their immediate enclosing scope. The lexical binding of an arrow function can’t be overridden, even with the new operator. Let’s now see how arrow function can be used to substitute the var self = this; statement.
var car = {
brand: "Nissan",
getBrand: function(){
// the arrow function keeps the scope of "this" lexical
var closure = () => {
console.log(this.brand);
};
return closure();
}
};

car.getBrand(); // output: Nissan
JS Bin

What You Need to Remember About this

We saw that the this keyword, like every other mechanism, follows some simple rules, and if we know them well, then we can use that mechanism with more confidence. So, let’s quickly recap what we have learned (from this and from the previous article):
  • this refers to the global object in the following cases:
    • in the outermost context, outside of any function block
    • in functions that are not methods of objects
    • in functions that are not object constructors
  • When a function is called as a property on a parent object, this refers to the parent object.
  • When a function is called using call() or apply(), or bind(), this refers to the first argument passed to these methods. If the first argument is null or not an object, this refers to the global object.
  • When a function is called with the new operator, this refers to the newly created object.
  • When an arrow function (introduced in ECMAScript 6) is used, this relies on lexical scope and refers to the parent object.
Knowing these straight and simple rules, we can easily predict what this will point to, and if it’s not what we want, we know which methods we can use to fix it.

Summary

JavaScript’s this keyword is a tricky concept to master, but with enough practice, master it you can. I hope that this article and my previous article, serve as good basis for your understanding and prove to be a valuable reference the next time this is causing you headaches.

Frequently Asked Questions (FAQs) about JavaScript’s ‘this’ Keyword

What is the ‘this’ keyword in JavaScript and why is it important?

The ‘this’ keyword in JavaScript is a special keyword that refers to the context in which a function is called. It’s a reference to the object that invoked the function. The value of ‘this’ can change depending on how a function is called, which makes it a powerful and flexible feature of JavaScript. Understanding ‘this’ is crucial for manipulating and interacting with objects, especially when working with object-oriented programming or when using frameworks and libraries that heavily rely on ‘this’.

How does the ‘this’ keyword work in different contexts?

The value of ‘this’ depends on how a function is invoked. In a method (a function inside an object), ‘this’ refers to the object it belongs to. In a regular function, ‘this’ refers to the global object (in browsers, it’s the window object). If a function is called with the ‘new’ keyword (as a constructor), ‘this’ refers to the newly created object. In event handlers, ‘this’ refers to the element that received the event. Lastly, ‘this’ can be explicitly set with call(), apply(), or bind().

What is the difference between ‘this’ in arrow functions and regular functions?

In regular functions, the value of ‘this’ is determined by how the function is called. However, arrow functions do not have their own ‘this’. Instead, they inherit ‘this’ from the parent scope at the time they are created. This makes arrow functions useful in situations where you want to preserve the context of ‘this’, such as in event handlers or callbacks.

How can I explicitly set the value of ‘this’ in a function?

JavaScript provides three methods to explicitly set the value of ‘this’ in a function: call(), apply(), and bind(). The call() and apply() methods call a function with a given ‘this’ value and arguments. The difference between them is that call() accepts an argument list, while apply() accepts a single array of arguments. The bind() method returns a new function, allowing you to specify the ‘this’ value when the function is called.

Why does ‘this’ inside a callback function refer to the global object?

When a callback function is invoked, it’s usually called as a regular function. In JavaScript, a regular function’s ‘this’ is either the global object or undefined (in strict mode). This can lead to unexpected results if you were expecting ‘this’ to refer to a different object. To work around this, you can use an arrow function for the callback (since it doesn’t have its own ‘this’), or use bind() to set the ‘this’ value.

How does ‘this’ behave in strict mode?

In strict mode, the value of ‘this’ in a function not associated with an object is undefined. This is a change from non-strict mode, where ‘this’ in a regular function refers to the global object. This change helps prevent bugs and makes code more predictable.

What is the ‘new’ keyword and how does it affect ‘this’?

The ‘new’ keyword in JavaScript is used to create an instance of an object type. When a function is called with ‘new’, it’s known as a constructor call. In a constructor call, ‘this’ refers to the newly created object. This allows you to add properties or methods to the object within the constructor function.

How does ‘this’ work in event handlers?

In event handlers, ‘this’ refers to the HTML element that received the event. This allows you to directly interact with the element within the event handler function. For example, you can change the element’s properties, call its methods, or access its child elements.

Can I use ‘this’ in object methods?

Yes, ‘this’ is commonly used in object methods. In a method, ‘this’ refers to the object it belongs to. This allows you to access and manipulate the object’s properties within the method.

What are some common pitfalls when using ‘this’ in JavaScript?

One common pitfall is assuming that ‘this’ within a function always refers to the function itself. In fact, ‘this’ refers to the object that invoked the function. Another common pitfall is using ‘this’ in a callback function or an event handler, where ‘this’ may not refer to what you expect. Understanding how ‘this’ works in different contexts and how to control its value can help avoid these pitfalls.

Ivaylo GerchevIvaylo Gerchev
View Author

I am a web developer/designer from Bulgaria. My favorite web technologies include SVG, HTML, CSS, Tailwind, JavaScript, Node, Vue, and React. When I'm not programming the Web, I love to program my own reality ;)

callbacksclosuresexecution contextjameshmethodsobjectsscopethis
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week