The `this` Keyword
โฑ๏ธ ~2-minute bite ยท solve the sandbox to master
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.| 1 | alice.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.
Why Should I Care?
โ The exact interview question + the bug it kills.Exact interview question
โWhat logs here, and why?โ
| 1 | const user = { |
| 2 | name: 'Ada', |
| 3 | greet() { return 'hi ' + this.name; }, |
| 4 | }; |
| 5 | const g = user.greet; |
| 6 | console.log(g()); // ? |
| 7 | console.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):
- new binding โ
new Foo()creates a fresh object and binds it; ignores everything below. - Explicit binding โ
.call/.apply/.bind. A hard-bound fn (bind) can't be re-bound except bynew. - Implicit binding โ
obj.fn()โ the base object. Only the last reference before the call counts (a.b.fn()โb). - Default binding โ bare
fn()โglobalThisin sloppy mode,undefinedin 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.How does `this` work inside a class field vs a class method?