The 'this' keyword in JS

The this keyword in JavaScript refers to the object of its current execution context. In other words, the value of this is determined based on how the function is called.

The main purpose of this is to give methods access to their objects and to make our code reusable by allowing us to execute the same code for multiple objects.

Let's explore how the this keyword gets its value and how we can stabilize it.


Global execution

The this keyword is immediately available. Open your DevTools in the console and type this. The value of this is the Window object.

// output: Window { …} console.log(this)

Invocation as function

If we are simply invoking a function statement or a function expression, the this keyword will also point to the Window object, because the function execution context is global.

function myFunction() { // output: Window { …} console.log(this) /* myVariable is on the global scope and it will be inside the Window object. */ this.myVariable = "global" }

Methods

A method is a function definition inside an object. We invoke methods with the dot notation: myObject.myMethod(). The execution context is myObject, and the this keyword points to current object.

const myObject = { myMethod: function () { // 'this' === myObject console.log(this) }, } myObject.myMethod()

However, if we add a new function inside myMethod, we create a new execution context and the this keyword now points to global scope.

const myObject = { myMethod: function () { setTimeout(function () { // output: Window { …} console.log(this) }) }, }

Next, we will explore a few ways to stabilize the value of this to prevent this unwanted behavior.


Assigning 'this' to a variable

We can explicitly point this to the current object by assigning its value to a variable. Example: var self = this; - This is an outdated solution commonly seen on legacy code.

const myObject = { myMethod: function () { var self = this setTimeout(function () { // self === myObject console.log(self) }) }, }

Bind

The bind() method sets the value of this to a particular value regardless of how it is called. In the following example, we explicitly bind this to the callback function to maintain its instance.

const myObject = { myMethod: function () { setTimeout( function () { // output: myObject { …} console.log(this) }.bind(this) ) }, }

Call and Apply

The call() and apply() methods, call a function with a given this value. The difference between the two methods relies on how they accept their arguments.

The first argument should be bound to this.

const wine = { name: "Bordeaux", price: 18.5, } function getProduct() { // output: The price of Bordeaux is 18.5 dlls. console.log(`The price of ${this.name} is ${this.price} dlls.`) } // this === wine by passing the wine object as an argument getProduct.call(wine) getProduct.apply(wine)

call() accepts an argument list as the second parameter.

const wine = { name: "Bordeaux", price: 18.5, } function getProduct(status, date) { // output: Bordeaux is not available today. console.log(`${this.name} is ${status} ${date}`) } getProduct.call(wine, "not available", "today")

apply() accepts a single array of arguments as the second parameter.

const wine = { name: "Bordeaux", price: 18.5, } function getProduct(params) { /* output: Bordeaux is not available today. */ console.log(`${this.name} is ${params[0]} ${params[1]}`) } getProduct.call(wine, ["not available", "today"])

Arrow functions (ES6)

In regular functions, the this keyword gets its value from the object that called the function. Arrow functions don't have binding of this and the this keyword always represents the object that defined the arrow function.

const myObject = { myMethod() { // this === myObject setTimeout(() => console.log(this)) }, }

Strict mode

Strict mode can help us prevent some silent errors by changing them to throw errors. The this keyword has some differences between strict mode and non-strict mode. In strict mode, the global this keyword is undefined.

"use strict" function myFunction() { // output: undefined console.log(this) }