← all writing

"this" Keyword in JavaScript with Arrow Functions

In JavaScript, this refers to the current execution context of a function. However, arrow functions handle this differently from regular functions. They inherit the this value from their containing (or surrounding) lexical context, which is essentially the context in which they are defined.

Unlike regular functions, arrow functions do not have their own this. Instead, they inherit the this value from the enclosing lexical context.

Example 1: Preserving the Value of this

class Counter {
  constructor() {
    this.count = 0;
  }
  increment() {
    setInterval(() => {
      console.log(this.count);   // `this` refers to the Counter instance
      this.count++;
    }, 1000);
  }
}
 
const counter = new Counter();
counter.increment();

In this example, the arrow function inside setInterval retains the this value of the Counter instance. Therefore, it can access and manipulate the count property.

Example 2: Using Arrow Functions in Callbacks

const button = document.querySelector('#myButton');
button.addEventListener('click', () => {
  console.log(this); // `this` refers to the global object (window in a browser)
});

Here, the arrow function inside the event listener captures the this value of its lexical context. As a result, it refers to the global object (window in a browser), not the button element.

Questions

A couple of these questions assume a classic, non-strict script context. In strict mode (and ES modules, which are strict by default), this at module top level is undefined, so accessing this.name would throw TypeError. Browser quirk: in a non-strict script tag, window.name is a legacy DOM property that defaults to an empty string "", not undefined — so what the book describes as "logs undefined" actually logs a blank line in DevTools. The teaching point — arrow functions don't bind to the calling object — is the same in every context.

1. What is the output of the following program?

const person = {
  name: "Deepak",
  skills: ["HTML", "CSS", "JS"],
  logSkills: function () {
    this.skills.forEach(skill => {
      console.log(`${this.name} can do ${skill}.`);
    });
  }
};
 
person.logSkills();

Answer:

Deepak can do HTML.
Deepak can do CSS.
Deepak can do JS.

2. What is the output of the following program?

const obj = {
  name: "Deepak",
  regularFunction: function () {
    console.log(this.name);
  },
  arrowFunction: () => {
    console.log(this.name);
  }
};
 
obj.regularFunction(); // What will this log?
obj.arrowFunction();   // What will this log?

Answer:

Deepak
undefined

Explanation: In the obj.regularFunction() call, this refers to the obj object, so it logs "Deepak". In the obj.arrowFunction() call, the arrow function captures this from its surrounding context, which is the global context, where this refers to the global object. Since there's no name property in the global context, it logs undefined. (See the note at the top of this section about the window.name browser quirk and strict mode.)

3. What will be logged when the button is clicked?

const button = document.getElementById("myButton");
 
const obj = {
  name: "Object",
  handleClick: () => {
    console.log(this.name);
  }
};
 
button.addEventListener("click", obj.handleClick);

Answer — undefined

Explanation: When the button is clicked, the arrow function obj.handleClick will be executed. However, arrow functions do not have their own this context; they capture the this value from their surrounding scope, which in this case is the global context. Since there is no name property defined in the global context, it will log undefined when the button is clicked.

4. What will be logged here?

const obj = {
  name: "Deepak",
  delayedLog: function () {
    console.log(this.name);
    setTimeout(() => {
      console.log(this.name);
    }, 1000);
  }
};
 
obj.delayedLog();

Answer:

Deepak
Deepak

Explanation: The delayedLog function is a regular function, and when we call obj.delayedLog(), it first logs "Deepak" because its this value is obj. However, in the setTimeout callback, which is an arrow function, this captures its value from its surrounding scope, which is the delayedLog function in this case. Consequently, it also logs "Deepak". If we were to change the setTimeout callback to a regular function instead of an arrow function, it would log undefined.