Skip to content
Sahil Durgia/ full-stack
2 min readJavaScript

`this` in JavaScript: Why It Confuses Everyone, and the Rule That Fixes It

this isn't determined by where a function is defined — it's determined by how it's called. One rule, four call patterns, one arrow-function exception.

JavaScriptthisfundamentals

Almost every other variable in JavaScript is scoped by where it's written. `this` is scoped by how the function is called — and that one difference is the entire source of the confusion.

The rule: look at the call site, not the definition

const user = {
  name: 'Sahil',
  greet() { return `Hi, ${this.name}`; },
};
user.greet();              // 'Hi, Sahil' — called as user.greet(), this = user

const detached = user.greet;
detached();                 // 'Hi, undefined' — called plain, this = undefined (strict mode)

Same function, same definition — different result, because it was called differently. That's the whole mechanism: `this` is bound at call time based on what's to the left of the dot, not at definition time based on where the function was written.

The exception: arrow functions

const timer = {
  seconds: 0,
  start() {
    setInterval(() => { this.seconds++; }, 1000); // arrow: this = timer, correctly
  },
};

Arrow functions don't have their own `this` at all — they capture `this` lexically, from the enclosing scope, exactly like a closure captures a variable. That's precisely why arrow functions fixed the classic "this is undefined inside my callback" bug that plagued pre-ES6 code, and it's why the rule for arrow functions is genuinely different from every other call pattern.

The four patterns, in priority order

  • new Fn() — this is the newly created object.
  • fn.call(obj) / fn.apply(obj) / fn.bind(obj) — this is explicitly set to obj.
  • obj.method() — this is obj (whatever is left of the dot at the call site).
  • Plain fn() — this is undefined in strict mode (or the global object in non-strict, sloppy mode).

Every `this` bug is a mismatch between which of these four patterns you think is happening and which one actually is — usually a method torn off its object and called plain (pattern 4) when the code assumed pattern 3. Once the call site, not the definition, is the thing you check, the bug becomes findable instead of mysterious.

Runnable example

The snippets above are the short version — the full, runnable code lives on GitHub.

View on GitHub ★
Keep reading
Next: 30 JavaScript interview questions, actually explained

The capstone of the JavaScript fundamentals series.