JavaScriptThe this Keyword

The this Keyword

this is one of the most-asked-about features of JavaScript, and most of the confusion goes away when you stop treating it as a variable and start treating it as a call-site mechanic. For regular functions, this is set at the moment the function is called, not where it is written. Arrow functions are the exception — they capture this from their surrounding scope.

Rule 1: regular function call

When you call a function as a plain function — fn()this is undefined in strict mode (which all modules and classes use), or the global object in sloppy mode.

JS
"use strict";

function whoAmI() {
  return this;
}

console.log(whoAmI());   // undefined
Rule 2: method call

When you call a function as a property of an object — obj.fn()this is that object. The function does not have to be defined inside the object; what matters is the dot at the call site.

JS
const user = {
  name: "Ada",
  greet() {
    return "Hello, " + this.name;
  },
};

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

// Pull the method off — no more dot
const greet = user.greet;
// console.log(greet());     // TypeError: cannot read 'name' of undefined
Detaching a method loses this
Assigning a method to a bare variable, or passing it as a callback, breaks the implicit receiver. `setTimeout(user.greet, 0)` calls it without an object, so `this` becomes `undefined`.
Rule 3: constructor call with new

Calling a function with new creates a fresh object and sets this to it for the duration of the call. The new object is returned automatically (unless the constructor explicitly returns another object).

JS
function Point(x, y) {
  this.x = x;
  this.y = y;
}

const p = new Point(3, 4);
console.log(p);   // Point { x: 3, y: 4 }
Rule 4: arrow functions — lexical this

Arrow functions do not have their own this. They use the this of the enclosing scope at the time the arrow was defined. That is exactly what you usually want for inner callbacks.

JS
class Timer {
  constructor() {
    this.seconds = 0;
  }
  start() {
    setInterval(() => {
      this.seconds++;            // `this` is the Timer — captured lexically
    }, 1000);
  }
}

// Compare with a regular function:
setInterval(function () {
  // this === undefined here (strict mode)
}, 1000);

Because arrows cannot have their own this, call, apply and bind are powerless to change it. They accept the argument and silently ignore it.

Rule 5: event handlers

When the DOM invokes a regular function as an event handler, this is the element the listener is attached to. With an arrow function, this is whatever it was outside.

JS
button.addEventListener("click", function () {
  // `this` is the button element
  this.classList.toggle("active");
});

button.addEventListener("click", () => {
  // `this` is whatever surrounds this code — usually not the button
  // use `event.currentTarget` instead if you need the element
});
call, apply and bind — explicit this

Every regular function has three methods that let you choose this manually.

  • fn.call(thisArg, a, b, c) — call the function now with thisArg and the listed arguments.

  • fn.apply(thisArg, [a, b, c]) — same, but arguments are an array.

  • fn.bind(thisArg, a, b) — return a new function that, when called, will use thisArg and the pre-bound arguments.

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

const user = { name: "Ada" };

console.log(greet.call(user, "Hi", "!"));        // Hi, Ada!
console.log(greet.apply(user, ["Hello", "."]));  // Hello, Ada.

const sayHi = greet.bind(user, "Hey");
console.log(sayHi("?"));                         // Hey, Ada?
The decision tree

To work out what `this` is at any call site, ask in order:

  • Is the function an arrow? Then this is whatever the surrounding scope says it is. Stop.

  • Was it called with new? Then this is the freshly-created object. Stop.

  • Was it called with call/apply/bind? Then this is whatever was passed. Stop.

  • Was it called as obj.fn() with a dot? Then this is obj. Stop.

  • Otherwise (a plain fn()), this is undefined in strict mode, or the global object in sloppy mode.

One sentence
`this` is set by the **call site**, not the definition — except for arrow functions, which lock it in at definition.
Practical advice
When in doubt, use an arrow for callbacks and method shorthand for methods. That covers ~95% of cases without ever reaching for `bind`.