๐Ÿณ IntuitiveFE
Login
โ† All concepts

The `this` Keyword

โฑ๏ธ ~2-minute bite ยท solve the sandbox to master

0%lesson
๐Ÿง’

5-Year-Old Metaphor

โ€” The physical, real-world picture. No jargon.

๐Ÿง’ `this` is a fingerprint left on whoever is holding the phone right now.

A function is a phone. When you call it, somebody is holding it โ€” that holder is this. It does not matter who made the phone or where it was kept. Only who is holding it at the moment of the call.

  • alice.call() โ†’ Alice is holding it โ†’ this = alice.
  • Drop the phone on the floor (const f = alice.call; f()) โ†’ nobody holds it โ†’ undefined.
  • .call(bob) โ†’ you physically shove the phone into Bob's hand.
  • An arrow function has no hands. It just keeps pointing at the room it was born in.
๐ŸŽ›๏ธ

Interactive Sandbox

โ€” Move something, see it react instantly.
๐Ÿงphone
๐Ÿ“ฑalice
๐Ÿงbob
๐Ÿงwindow/undefined
๐ŸงnewObj
๐ŸงbornRoom
js
1alice.whoHoldsMe()

// this resolves to โ†’ alice

Called as a method โ†’ `this` is whatever is left of the dot.

๐ŸŽฏ

Challenge

Hand the phone to BOB without touching the object it lives on.

Try it
๐ŸŽฏ

Why Should I Care?

โ€” The exact interview question + the bug it kills.

Exact interview question

โ€œWhat logs here, and why?โ€

js
1const user = {
2 name: 'Ada',
3 greet() { return 'hi ' + this.name; },
4};
5const g = user.greet;
6console.log(g()); // ?
7console.log(user.greet()); // ?

Answer: g() โ†’ hi undefined (lost holder), user.greet() โ†’ hi Ada.

Production bug it solves

Passing a class method as a callback โ€” onClick={this.handleClick} โ€” and getting โ€œCannot read properties of undefinedโ€. The handler got ripped off its object. Fix: bind in the constructor, or use a class field arrow (handleClick = () => {โ€ฆ}), which has no hands and keeps the instance.

๐Ÿ”ฌ

The Deep Dive

โ€” Spec refs, engine internals, the minutiae.

The four binding rules, in precedence order (highest wins):

  1. new binding โ€” new Foo() creates a fresh object and binds it; ignores everything below.
  2. Explicit binding โ€” .call / .apply / .bind. A hard-bound fn (bind) can't be re-bound except by new.
  3. Implicit binding โ€” obj.fn() โ†’ the base object. Only the last reference before the call counts (a.b.fn() โ†’ b).
  4. Default binding โ€” bare fn() โ†’ globalThis in sloppy mode, undefined in strict (ES5 ยง10.4.3 / ES2015 strict).

Arrows are special: they have no [[ThisMode]]: lexical binding โ€” the spec (ES2015 ยง14.2) resolves this via the enclosing environment record, so .call on an arrow is a no-op for this.

In V8, this isn't a variable in the local scope; it's a receiver slot on the activation. That's why arrows can skip it entirely โ€” no slot, walk up the scope chain.

๐ŸŽค

Interview Questions

โ€” Real questions from real interviews โ€” with answers.

new > explicit (.call/.bind) > implicit (obj.fn()) > default (global/undefined).

Extracting a method breaks the implicit binding โ€” there's no longer a dot-call receiver.

Arrow functions have no own `this` binding โ€” they capture it from their enclosing lexical scope at creation time.

`.call` invokes immediately with args listed; `.apply` invokes immediately with args as array; `.bind` returns a new permanently-bound function.

Prototype methods share one function; class field arrows create a new function per instance.

`new` creates a fresh object linked to the constructor's prototype, then calls the function with it as `this`; returning a non-primitive overrides it.

๐ŸŽฎ

Memory Game

โ€” Quick quiz โ€” lock the concept in long-term memory.
1/4

How does `this` work inside a class field vs a class method?