Understanding `this` in JavaScript: Arrow Functions vs Function Keyword

If you’ve been writing JavaScript for a while, chances are you’ve run into one of the most confusing keywords: this. Sometimes it gives you what you expect, sometimes it doesn’t — and suddenly your console.log shows undefined.

Let’s clear up the confusion with a practical example.


Example 1: Using an Arrow Function

const user = {
  name: "Virat",
  greet: function () {
    setTimeout(() => {
      console.log(`${this.name}`);
    });
  },
};

user.greet(); // Output: "Virat"

✅ Here, the output is "Virat".

Why?

  • Arrow functions don’t have their own this.

  • Instead, they inherit it from the surrounding scope (lexical scoping).

  • In this case, the surrounding scope is the greet method, and inside greet, this refers to the user object.

So this.name"Virat".


Example 2: Using a Regular Function

const user1 = {
  name: "Chetana",
  greet: function () {
    setTimeout(function () {
      console.log(`${this.name}`);
    });
  },
};

user1.greet(); // Output: undefined

❌ Here, the output is undefined.

Why?

  • Regular functions create their own this at runtime.

  • In the setTimeout callback, this doesn’t point to user1.

  • Instead, it defaults to the global object (window in browsers, global in Node.js).

  • Since the global object doesn’t have a name property, we get undefined.


Story Analogy: Arrow vs Regular Functions

Imagine you’re in a restaurant.

  • A regular function is like a new waiter who introduces themselves and forgets who you are. When they take your order, they don’t remember which table you’re sitting at.

  • An arrow function is like a waiter’s assistant who doesn’t introduce themselves. They simply shadow the main waiter and remember exactly which table (context) the main waiter is serving.

That’s the difference in how this is handled!


Fixing the Regular Function Example

If you still want to use the function keyword, you have a couple of options:

Option 1: Save this in a variable

const user1 = {
  name: "Chetana",
  greet: function () {
    const self = this; // capture this
    setTimeout(function () {
      console.log(self.name);
    });
  },
};

user1.greet(); // "Chetana"

Option 2: Use .bind(this)

const user1 = {
  name: "Chetana",
  greet: function () {
    setTimeout(function () {
      console.log(this.name);
    }.bind(this));
  },
};

user1.greet(); // "Chetana"

Key Differences Between Arrow Functions and Regular Functions

  1. this binding

    • Arrow → inherits from parent scope.

    • Regular → depends on how the function is called.

  2. Constructors

    • Arrow → ❌ can’t be used as constructors.

    • Regular → ✅ can act as constructors with new.

  3. Arguments object

    • Arrow → ❌ no own arguments object.

    • Regular → ✅ has its own arguments.


Takeaway

  • Use arrow functions when you want to preserve the outer this (e.g., callbacks, async code).

  • Use regular functions when you need your own this (e.g., object methods, constructors).

Mastering the difference saves hours of debugging weird undefined logs and makes your code much more predictable.

0
Subscribe to my newsletter

Read articles from Virat Srivastava directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Virat Srivastava
Virat Srivastava