Understanding the dynamic nature of the ‘this’ keyword in JavaScript

In this article, we will analyze the dynamic behavior of the this keyword and learn what it points to when used in different scenarios. But first, let's have a high-level understanding of the concept:

Now, let's take a closer look at what the this keyword points to in various scenarios.

In the global scope

The this keyword, when used in the global scope, points to the global Window object, as you can see in the following example:

console.log(this); // Window

In a regular function

When using JavaScript in strict mode, the this keyword in a function declaration or expression results in undefined.

'use strict';

function welcome() {
  console.log(this); // undefined
}

welcome();

However, when using JavaScript without strict mode, the this keyword in a function declaration or expression points to the global Window object.

function welcome() {
  console.log(this); // Window
}

welcome();

In an arrow function

The this keyword behaves slightly differently in an arrow function and points to the parent scope of the function.

const welcome = () => {
  console.log(this); // Window
};

welcome();

As you can see in the above example, the this keyword points to the global Window object, which is the parent scope of the function. For this behavior, the this keyword in an arrow function is referred to as the lexical this keyword.

Along with the behavior of the this keyword, there are a few other differences between a regular and an arrow function. I have an article on Regular function vs arrow function in JavaScript if you are interested in learning the differences.

In a constructor function

The this keyword, when used in a constructor function, points to the object that is created using it.

function Person(name, age) {
  console.log(this); // Person {}
  this.name = name;
  this.age = age;
  console.log(this); // Person { name: 'John', age: 30 }
}

new Person('John', 30);

As you can see in the above code, when a constructor function is called with the new keyword, it creates an empty Person object and sets the object as the value of the this keyword.

As a result, we can then use the this keyword to create properties (e.g., name and age) within the object and assign their values with the provided arguments.

In an object method

When a regular function is used as an object method, the this keyword points to the object that calls the method.

const john = {
  name: 'John',
  greet() {
    console.log(`Good morning ${this.name}`); // Good morning John
  },
};

john.greet();

In the above code, the this keyword within the greet method points to the john object. However, the behavior changes when we borrow the method from john to another object matt.

const john = {
  name: 'John',
  greet() {
    console.log(`Good morning ${this.name}`);
  },
};

const matt = {
  name: 'Matt',
};

matt.greet = john.greet;
matt.greet(); // Good morning Matt

Here, the this keyword now points to the matt object. Do you notice the difference? It is a subtle but important distinction to keep in mind.

On the other hand, if you change the method from a regular function to an arrow function, the this keyword will, as usual, point to its parent scope, as demonstrated in the following example.

const john = {
  name: 'John',
  greet: () => {
    console.log(`Good morning ${this.name}`); // Good morning undefined
  },
};

john.greet();

Here, as an object literal doesn't create a scope in JavaScript, the parent scope of the greet method is the global Window object, which doesn't have a property name. So this.name results in undefined.

In the DOM

The this keyword in a regular event listener function points to the DOM element, as shown in the following example:

function handleClick() {
  console.log(this); // <h1 id="title">Learning the this keyword</h1>
}

document.getElementById('title').addEventListener('click', handleClick);

On the other hand, in an arrow event listener function, the this keyword, as usual, points to its parent scope, which in this case is the global Window object.

const handleClick = () => {
  console.log(this); // Window
};

document.getElementById('title').addEventListener('click', handleClick);

It's worth noting that in the browser environment, where the this keyword points to the global Window object, in the Node.js environment, it points to an empty object, except for a function declaration or expression in non-strict mode, where it points to the Node.js Global object.

There you have it! I hope you've learned a thing or two from this article. Writing some code and experiencing the behavior for yourself will further solidify your learning.

The this keyword is one of three topics of a JavaScript execution context. If you are interested in learning the other two topics, I recommend checking out the articles on Exploring the scope and scope chain in JavaScript, as well as Understanding the variable environment and hoisting in JavaScript for further insights.

Share this article with your friends

Copy URL

Elevate your JavaScript and freelance journey

Supercharge your JavaScript skills and freelance career. Subscribe now for expert tips and insights!