Skip to main content

Command Palette

Search for a command to run...

Understanding the this Keyword in JavaScript

Updated
5 min read
Understanding the this Keyword in JavaScript

What Is this?

In JavaScript, this is a special keyword that refers to the object that is currently calling the function. It is not fixed at the time you write the function — it is determined at the time the function is called.

Think of it like a nametag that gets filled in at the moment someone picks up the phone:

Who called this function right now?
That caller → that's `this`.

This single idea explains almost every this behaviour you'll encounter.


this in the Global Context

When you use this outside of any function or object — at the top level of your script — it refers to the global object.

console.log(this); // In a browser → Window object

In a browser, the global object is window. So this === window at the top level.

var name = "JavaScript";
console.log(this.name); // "JavaScript"
// same as window.name

Note: In Node.js, the global object is global, not window. And in ES modules (type="module"), this at the top level is undefined.


this Inside Objects

When a function is called as a method of an object, this refers to that object — the one before the dot.

const user = {
  name: "Arjun",
  greet() {
    console.log("Hello, I am " + this.name);
  }
};

user.greet(); // "Hello, I am Arjun"

Here, user.greet() is called on user. So inside greet, this is user. The dot tells you who the caller is.

Let's prove that this is truly dynamic:

const admin = {
  name: "Priya"
};

admin.greet = user.greet; // same function, different caller

admin.greet(); // "Hello, I am Priya"

Same function. Different caller. Different this. This is the core behaviour.


this Inside Regular Functions

When a function is called standalone (not as a method), the caller is the global object — or undefined in strict mode.

function sayHello() {
  console.log(this);
}

sayHello(); // Window (browser) or undefined (strict mode)
"use strict";

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

sayHello();

In strict mode, JavaScript does not default this to the global object. This is intentional — it prevents accidental global variable pollution.

The Classic Trap: Method Detached from Object

const user = {
  name: "Arjun",
  greet() {
    console.log("Hello, " + this.name);
  }
};

const fn = user.greet; // detached — no longer called on user
fn(); // "Hello, undefined"

fn() has no caller object. So this defaults to global (or undefined in strict mode), and this.name is undefined. The function is the same — but the calling context changed.


How Calling Context Changes this

JavaScript gives you three explicit ways to control what this is: call, apply, and bind.

call() — Call with a specific this

function greet() {
  console.log("Hello, " + this.name);
}

const user = { name: "Arjun" };

greet.call(user); // "Hello, Arjun"

call() invokes the function immediately, with user as this.

apply() — Same as call, but arguments as an array

function introduce(city, country) {
  console.log(`\({this.name} from \){city}, ${country}`);
}

introduce.apply(user, ["Mumbai", "India"]);
// "Arjun from Mumbai, India"

bind() — Returns a new function with this permanently set

const boundGreet = greet.bind(user);
boundGreet(); // "Hello, Arjun"

// Even if you try to call it on another object, this stays as user
boundGreet.call({ name: "Someone else" }); // still "Hello, Arjun"

bind creates a new function where this is permanently locked — no matter how it is later called.


Arrow Functions: this Is Inherited, Not Assigned

Arrow functions are different. They do not have their own this. Instead, they inherit this from the surrounding scope where they were defined.

const user = {
  name: "Arjun",
  greet() {
    const inner = () => {
      console.log(this.name); // inherits `this` from greet()
    };
    inner();
  }
};

user.greet(); // "Arjun" ✅

Compare this with a regular function:

const user = {
  name: "Arjun",
  greet() {
    function inner() {
      console.log(this.name); // own `this` → undefined in strict mode
    }
    inner();
  }
};

user.greet(); // undefined ❌

Arrow functions are the idiomatic solution for callbacks inside methods, because they don't reset this.

const timer = {
  name: "Countdown",
  start() {
    setTimeout(() => {
      console.log(this.name + " started!"); // ✅ works
    }, 1000);
  }
};

timer.start(); // "Countdown started!"

Quick Summary Table

Context What this is
Global scope (browser) window
Global scope (strict mode) undefined
Object method (obj.fn()) obj
Standalone function call window / undefined
call(obj) / apply(obj) obj
bind(obj) obj (permanently)
Arrow function Inherited from outer scope

The One Rule to Remember

this is always the object to the left of the dot when the function is called. If there's no dot, it's the global object (or undefined in strict mode). Arrow functions don't play this game — they borrow this from where they were born.

Once you internalise this, debugging this-related bugs becomes straightforward: trace back to where the function was called, not where it was defined.


Putting It All Together

const bank = {
  owner: "Arjun",
  balance: 5000,

  // Regular method — `this` is the caller
  showBalance() {
    console.log(`\({this.owner}'s balance: ₹\){this.balance}`);
  },

  // Arrow inside method — inherits `this`
  delayedShow() {
    setTimeout(() => {
      console.log(`Delayed: \({this.owner} has ₹\){this.balance}`);
    }, 500);
  }
};

bank.showBalance();   // "Arjun's balance: ₹5000"
bank.delayedShow();   // "Delayed: Arjun has ₹5000"

// Detach and call standalone
const fn = bank.showBalance;
fn();                 // "undefined's balance: ₹undefined"

// Fix with bind
const fixed = bank.showBalance.bind(bank);
fixed();              // "Arjun's balance: ₹5000"