Posts

JavaScript 'this' Explained

JavaScript’s this is not difficult because it does many things. It is difficult because one small word changes value based on how a function is called. That makes this look unpredictable when the real problem is …

April 27, 2026 5 min read 938 words

In this article

JavaScript’s this is not difficult because it does many things. It is difficult because one small word changes value based on how a function is called.

That makes this look unpredictable when the real problem is usually that we are looking in the wrong place.

For an ordinary function, do not start with where the function was written. Start with the call-site.

The call usually decides this.

That one rule explains most of the behavior you will meet in day-to-day JavaScript.

Scope Is Not this

Scope answers this question:

Where can JavaScript find this variable?

this answers a different question:

What value is this function being called with as its receiver?

Consider a regular method:

const user = {
  name: 'Ada',
  sayName() {
    console.log(this.name);
  }
};

user.sayName();
// Ada

JavaScript does not search outward through lexical scopes to find this. The call user.sayName() supplies user as the receiver.

user.sayName()
^^^^
this points here

That is the first useful mental model: look to the left of the dot at the call-site.

A diagram showing user.sayName pointing this at user, while a detached sayName call has no object receiver.

Method Calls Provide a Receiver

The property that stores a function does not permanently attach that function to the object. The object matters when the function is called through it.

function introduce() {
  console.log(`Hi, I am ${this.name}.`);
}

const ada = {
  name: 'Ada',
  introduce
};

const grace = {
  name: 'Grace',
  introduce
};

ada.introduce();
// Hi, I am Ada.

grace.introduce();
// Hi, I am Grace.

It is the same function in both objects. The receiver changes because the call-site changes.

Detached Methods Lose Their Receiver

Now take the method out of the object:

const user = {
  name: 'Ada',
  sayName() {
    console.log(this.name);
  }
};

const sayName = user.sayName;

sayName();

The final call is no longer user.sayName(). It is a plain sayName() call, so user is not supplied as the receiver.

In strict mode, this is undefined for that plain function call, and reading this.name throws a TypeError. In a classic non-strict browser script, this may fall back to globalThis. Modules and class bodies are strict, so relying on the fallback is a fine way to manufacture a bug that changes when code moves.

The function did not forget user. It was never permanently bound to user in the first place.

Set this Explicitly with call, apply, or bind

JavaScript also lets you choose the receiver.

Use call for Individual Arguments

function greet(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}

const user = { name: 'Ada' };

console.log(greet.call(user, 'Hello', '!'));
// Hello, Ada!

The first argument to call becomes this. The remaining values become function arguments.

Use apply for an Array of Arguments

console.log(greet.apply(user, ['Welcome', '.']));
// Welcome, Ada.

apply does the same receiver selection but accepts the function arguments in an array-like value.

Use bind to Create a Bound Function

const greetAda = greet.bind(user);

console.log(greetAda('Good morning', '!'));
// Good morning, Ada!

bind does not call greet immediately. It creates a new function whose this value is fixed to user for normal calls.

This is useful when you must pass a method as a callback but still need its receiver:

const user = {
  name: 'Ada',
  sayName() {
    console.log(this.name);
  }
};

setTimeout(user.sayName.bind(user), 100);
// Ada

Constructor Calls Create this

Calling a constructable function with new follows another rule: JavaScript creates a new object and supplies it as this.

function User(name) {
  this.name = name;
}

const ada = new User('Ada');

console.log(ada.name);
// Ada

At a practical level, new User('Ada') does this work:

  1. Creates a new object linked to User.prototype.
  2. Calls User with that object as this.
  3. Returns the new object unless the constructor explicitly returns a different object.

Classes package this behavior in clearer syntax, but the receiver rule is still doing the work underneath.

Nested Regular Functions Get Their Own this

A regular function inside a method does not automatically inherit the method’s receiver.

const counter = {
  count: 0,
  start() {
    setTimeout(function () {
      console.log(this === counter);
      // false
    }, 100);
  }
};

counter.start();

The callback is invoked later by the timer machinery. It is not called as counter.callback(), so it does not receive counter as this.

You can solve that with bind, an ordinary variable captured through closure, or an arrow function. Arrow functions use a different this rule, so I cover that separately in JavaScript Arrow Functions Explained.

The Practical Lookup Order

When an ordinary function uses this, inspect the call in this order:

  1. Was it called with new? The newly created object becomes this.
  2. Was it called with call, apply, or a function created by bind? The explicitly supplied value is used.
  3. Was it called through an object, as in object.method()? That object is the receiver.
  4. Was it called as a plain function? Strict mode uses undefined; non-strict code may substitute globalThis.

There are specification details and edge cases behind those rules, but this checklist handles the bugs most developers actually need to diagnose.

Quick Recap

  • this is not lexical scope.
  • An ordinary function usually gets this from its call-site.
  • object.method() supplies object as the receiver.
  • Detaching a method also detaches that receiver.
  • call, apply, and bind let you choose this explicitly.
  • new supplies a newly created object as this.
  • Arrow functions do not follow these rules because they do not define their own this.

When this looks mysterious, find the call. The mystery usually gets much smaller from there.

-Rob