Understanding this in JavaScript: A Complete Guide with Examples

pushpesh kumarpushpesh kumar
4 min read

The this keyword in JavaScript is one of the most misunderstood concepts, yet it's fundamental to writing effective code. It refers to the execution context and behaves differently depending on how a function is called.

In this article, you'll learn:
✔️ What this refers to in different contexts.
✔️ Key rules governing this.
✔️ Practical examples to solidify your understanding.

What is this?

this is a special keyword that points to an object—the one currently executing the code. Its value depends entirely on how a function is called, not where it's defined.


Rules of this in JavaScript (The 5 Key Scenarios)

Here are the five most common scenarios where this behaves differently:

1. Default Binding (Global or undefined in Strict Mode)

  • When used in a regular function (not an object method or event), this refers to:

    • window (in browsers) in non-strict mode.

    • undefined in strict mode.

Example (Non-strict mode):

function sayHello() {
  console.log(this);   // window (global object in browser)
}
sayHello();

Example (Strict mode):

"use strict";
function sayHello() {
  console.log(this);   // undefined
}
sayHello();

2. Implicit Binding (this in Object Methods)

  • When a function is called as a method of an object, this refers to the object itself.

Example:

const user = {
  name: "Alice",
  greet() {
    console.log(`Hello, ${this.name}!`); // `this` = user
  },
};

user.greet(); // "Hello, Alice!"

⚠️ Pitfall: If you extract the method (e.g., const greetFunc = user.greet), this may get lost!

❓ What’s wrong?

  • You saved the function to a new variable greetFunc

  • Now you're calling it without an object, so it's just a plain function call

  • In strict mode, this becomes undefined

  • In non-strict mode, this becomes the global object (window in browsers)

  • SO this line console.log(Hello, ${this.name}!);

  • Will try to access: undefined.name → causes error or prints "Hello, undefined!"

How to fix this: const greetFunc = user.greet.bind(user); greetFunc(); // "Hello, Alice!"


3. Explicit Binding (Forcing this with call, apply, bind)

  • You can force what this refers to using:

    • func.call(obj, args) → Calls func with obj as this.

    • func.apply(obj, [args]) → Same as call but takes an array of args.

    • func.bind(obj) → Returns a new function permanently bound to obj.

Example (call and apply):

function introduce(lang) {
  console.log(`${this.name} codes in ${lang}.`);
}

const dev = { name: "Bob" };

introduce.call(dev, "JavaScript");   // "Bob codes in JavaScript."
introduce.apply(dev, ["Python"]);    // "Bob codes in Python."

Example (bind):

const boundFunc = introduce.bind(dev, "TypeScript");
boundFunc(); // "Bob codes in TypeScript."

4. new Binding (this in Constructor Functions & Classes)

  • When a function is called with new, this refers to the newly created instance.

Example (Constructor Function):

function Person(name) {
  this.name = name;
  console.log(this); // Person { name: "Charlie" }
}

const person = new Person("Charlie");

Example (Class Syntax):

class User {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(`Hi, I'm ${this.name}.`);
  }
}

const user = new User("Dana");
user.greet(); // "Hi, I'm Dana."

5. Arrow Functions (Lexical this)

  • Unlike normal functions, arrow functions don’t have their own this.

  • They inherit this from their parent scope.

Example:

const obj = {
  name: "Eve",
  greet: () => {
    console.log(`Hi from ${this.name}.`); // `this` ≠ obj!
  }
};

obj.greet(); // "Hi from undefined." (inherits global/undefined `this`)

Good Use Case for Arrow Functions (Event Handlers):

class Button {
  constructor() {
    this.button = document.querySelector("button");
    this.button.addEventListener("click", () => {
      console.log(this); // `this` = Button instance
    });
  }
}

Common Pitfalls & Fixes

Problem: Losing this in Callbacks

const user = {
  name: "Frank",
  greet() {
    setTimeout(function() {
      console.log(`Hello, ${this.name}!`); // `this` = window/undefined
    }, 1000);
  }
};

user.greet(); // "Hello, !"

Fix: Use an arrow function to preserve this:

setTimeout(() => {
  console.log(`Hello, ${this.name}!`); // `this` = user (lexically bound)
}, 1000);

or bind:

setTimeout(function() {
  console.log(`Hello, ${this.name}!`);
}.bind(user), 1000);

Summary of this Rules

ScenarioWhat this refers to
Default Bindingwindow (non-strict) / undefined (strict)
Method Call (obj.func())The object (obj)
Explicit Binding (call, apply, bind)The provided object (obj)
new Binding (new Class())The newly created instance
Arrow FunctionsInherited from parent scope

Final Thoughts

The this keyword is context-dependent, but once you understand the core rules, it becomes easy to predict. Key takeaways:

  • ☑️ Use call/apply/bind for explicit control.

  • ☑️ Arrow functions inherit this (=>function).

  • ☑️ new creates a new this object.

0
Subscribe to my newsletter

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

Written by

pushpesh kumar
pushpesh kumar