All topics
Objectsintermediate

The this Keyword in Depth

How the value of this is determined dynamically at call time based on four binding rules, rather than lexically like a normal variable.

this is one of the most misunderstood parts of JavaScript because, unlike almost every other identifier, its value isn't determined by where a function is written but by how it's called — a fundamentally different resolution rule that trips up developers coming from lexically-scoped languages. Interviewers lean on this heavily because a handful of short code examples can reveal whether you truly understand the binding rules or have just memorized common patterns.

this is like a name tag that gets handed to you fresh at the door of every single meeting you walk into (call site) — which meeting you're currently in determines what your tag says, rather than the tag being permanently stitched onto your shirt.

Key Concepts

1
There are effectively four binding rules, checked in a specific precedence order. Default binding: a bare function call (foo()) binds this to the global object in non-strict mode, or to undefined in strict mode (including inside ES modules and classes, which are strict by default). Implicit binding: calling a function as a method of an object (obj.foo()) binds this to that object at the moment of the call. Explicit binding: using call, apply, or bind overrides whatever this would otherwise be, forcing it to the object you specify. new binding: calling a function with new creates a brand-new object, binds this to it for the duration of the constructor call, and returns that object (unless the constructor explicitly returns a different object).
Default bindingImplicit bindingExplicit binding`new` bindingfoo()
2
Arrow functions are a deliberate exception to all four rules: they have no this binding of their own at all, and any reference to this inside one is resolved lexically, exactly like closing over an outer variable — looking outward to whatever this was bound to in the nearest enclosing non-arrow function or module scope.
this
3
The classic real-world bug this causes is passing an object method as a bare callback (setTimeout(obj.method, 100)), which strips the implicit binding since the function is now called bare, defaulting this to undefined or the global object rather than obj. The fixes are exactly the tools covered elsewhere: .bind(obj), wrapping the call in an arrow function, or defining the method itself as an arrow function class field so it captures this lexically from the surrounding class body at construction time.
setTimeout(obj.method, 100)thisundefinedobj.bind(obj)