The this Keyword

this is a special word that means "whoever is calling me right now" — and the tricky part is that its meaning can change every single time a function runs.

What Is this?

In most other places in JavaScript, a word means the same thing no matter where you use it. this is different. Inside a function, this refers to whatever object called that function — and that can be a different object every time the same function runs.

const user = {
  name: "Maya",
  greet() {
    return `Hi, I'm ${this.name}`;
  }
};

user.greet(); // "Hi, I'm Maya" — this.name means "the name property of whatever is left of the dot"

The key idea: this is not decided when a function is written — it's decided when a function is called. The exact same function can have a completely different this depending on how you call it.

🪞 Real-life analogy

Imagine a name tag that says "I am ___" but the blank only fills in the moment someone reads it out loud, based on who's wearing it at that exact second. Hand the same name tag to Maya, and it says "I am Maya." Hand it to Sam, and the exact same tag now says "I am Sam." The tag (the function) doesn't change — only who's currently wearing it (how it's called) changes what this means.

Rule 1: Called as an Object Method → this Is the Object

const car = {
  brand: "Toyota",
  describe() {
    return `This is a ${this.brand}`;
  }
};

car.describe(); // "This is a Toyota" — this = car, because car is left of the dot

Whatever sits directly to the left of the dot when a function is called becomes this inside that function. This is the single most common way this is used.

Rule 2: Called Alone → this Is undefined (or the Global Object)

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

whoAmI(); // undefined in strict mode / modules; the global object in old-style non-strict scripts

When a regular function is called all by itself, with nothing before the dot, there's no object to point to. Modern JavaScript (modules, classes, and anything in "use strict" mode) makes this undefined in that case, which helps catch bugs early instead of silently pointing at the browser's global window object.

Rule 3: Arrow Functions Don't Have Their Own this

const user = {
  name: "Maya",
  greetArrow: () => {
    return `Hi, I'm ${this.name}`;
  }
};

user.greetArrow(); // "Hi, I'm undefined" — arrow functions grab `this` from where they were WRITTEN, not called

This is the single biggest source of this confusion. Arrow functions never get their own this — instead, they permanently "inherit" whatever this was in the surrounding code at the moment they were defined. This is usually a problem for object methods, but incredibly useful inside callbacks (see below).

Where Arrow Functions Actually Help: Callbacks

const timer = {
  seconds: 0,
  start() {
    setInterval(() => {
      this.seconds++; // this still refers to `timer`, because arrow functions inherit `this`
      console.log(this.seconds);
    }, 1000);
  }
};

timer.start();

If start() had used a regular function() {} inside setInterval, that inner function would be called by the timer system itself (with no object before a dot), so this would become undefined — breaking this.seconds++. The arrow function sidesteps the whole problem by never having its own this at all; it just reuses start()'s this, which correctly points to timer.

Rule 4: Explicit Binding — call(), apply(), and bind()

Sometimes you want to control exactly what this should be, rather than relying on how a function happens to get called. Three built-in methods let you set it directly:

function introduce() {
  return `I'm ${this.name}`;
}

const person = { name: "Sam" };

introduce.call(person);        // "I'm Sam" — runs immediately, this = person
introduce.apply(person);       // "I'm Sam" — same as call, but takes arguments as an array

const boundIntroduce = introduce.bind(person);
boundIntroduce();                     // "I'm Sam" — bind() doesn't run it, it returns a NEW function permanently locked to `person`
  • call(thisValue, arg1, arg2...) — runs the function right away, with this set to whatever you pass in, and arguments listed one by one
  • apply(thisValue, [arg1, arg2]) — identical to call, but arguments are passed as a single array
  • bind(thisValue) — doesn't run the function at all; it hands back a brand new function with this permanently locked, ready to be called (or passed around) later

bind() is especially common when passing a method as a callback — for example, an event handler — where it would otherwise lose track of its original object.

Rule 5: new — this Is a Brand New Object

function Dog(name) {
  this.name = name; // this = the new object being built
}

const rex = new Dog("Rex");
rex.name; // "Rex"

When a function is called with new (including a class constructor), JavaScript creates a fresh, empty object first, then calls the function with this pointing at that brand new object. This is exactly how classes build this.property = value assignments inside their constructor, as covered in the Classes lessons.

Quick Reference: How this Is Decided

How the function is calledWhat this becomes
obj.method()The object left of the dot (obj)
plainFunction()undefined (strict mode) or the global object
func.call(x) / func.apply(x)Whatever you explicitly pass as x
const bound = func.bind(x)Permanently locked to x, forever
new Func()The brand new object being constructed
Arrow function () => {}Whatever this was in the surrounding code where it was written — never its own

Common Mistakes

⚠ Watch out for
  • Using an arrow function for an object's method — it won't have its own this, so this.property inside it silently fails or grabs the wrong value.
  • Passing a method as a callback without binding it — button.addEventListener("click", user.greet) loses user as this; you need user.greet.bind(user) or an arrow-function wrapper.
  • Assuming this is decided by where a function is defined — for regular functions, it's always decided by how the function is called, which can be surprising.

Best Practices

  • Use a regular function (or method shorthand) for object methods, so this correctly refers to the object.
  • Use arrow functions for callbacks nested inside a method, so they inherit the outer, correct this.
  • Reach for .bind() when you need to hand a method off somewhere else (like an event listener) and still want this to point back to the original object.

Performance Notes

Determining this has no real performance cost — it's a normal part of how a function call is set up. bind() does create a brand new function each time it's called, so avoid calling .bind() repeatedly inside a hot loop; bind once and reuse the result.

Browser Compatibility

call, apply, and function-based this rules have existed since JavaScript's earliest versions. Arrow functions and their special "no own this" behavior are newer (ES6, 2015) but supported in all current browsers.

Interview Questions

What determines the value of this inside a regular function?

How the function is called, not where it's defined — specifically, whatever object appears directly before the dot at the call site, or the object explicitly passed via call/apply/bind/new.

Why do arrow functions behave differently with this?

Arrow functions don't create their own this binding at all. Instead, they permanently use the this value from the surrounding scope where they were written, which makes them ideal for callbacks that need to reuse an outer method's this.

✏️ Exercise

Create an object counter with a count property and an increment() method that adds 1 to this.count. Call it a few times and log counter.count.

🧠 Quiz

1. Does an arrow function ever get its own this?

No — it always inherits this from the scope surrounding where it was defined.

2. What does bind() return?

A brand new function with this permanently locked to the value you provided — it does not run the function immediately.

🚀 Mini Challenge

Write an object clock with a time property and a start() method that uses setInterval with an arrow function to increase this.time by 1 every second, logging the new value each time. Explain in a comment why an arrow function is required here instead of a regular function.

Summary

  • this is decided by how a function is called, not where it's written — except for arrow functions.
  • Object methods get this pointing at the object before the dot; standalone calls get undefined.
  • call/apply/bind let you set this explicitly; new sets it to a freshly created object.

Related Topics

MDN reference: developer.mozilla.org → JavaScript → this (placeholder — add live link)