The four rules of this: how JavaScript decides what this is
this is set by how a function is called, not where it is written. Learn the four binding rules, their order, and why passing a method as a callback loses this.
Comes up in: JavaScript, Recruiter screen
Learn#
Tara writes button.addEventListener("click", cart.checkout). Clicking throws “Cannot read properties of undefined (reading ‘items’)”. cart.checkout() works fine in the console. Same function — different this.
this is not decided where a function is written. It is decided by how it is called. Four rules:
- Method call:
obj.fn()—thisis the object before the dot, the receiver. This is implicit binding.
- Plain call:
fn()—thisisundefinedin strict code (modules, classes), or the global object in sloppy scripts.
- Explicit:
fn.call(x),fn.apply(x)orfn.bind(x)—thisisx.
new:new Fn()—thisis a brand-new object.
function hello() { return "Hi, " + this.name; }
const user = { name: "Asha", hello };
console.log(user.hello());
const loose = user.hello;
try { loose(); } catch (e) { console.log(e.name + ": " + e.message); }
console.log(loose.call({ name: "Ravi" }));
function Person(name) { this.name = name; }
console.log(new Person("Mei").name);Output (verified)
Hi, Asha TypeError: Cannot read properties of undefined (reading 'name') Hi, Ravi Mei
Passing cart.checkout as a callback copies only the function, so it is later called plainly — rule 2. That is Tara’s bug. (Error text is from V8.)
call
- user.hello()
this
- user
Console
- Hi, Asha
user.hello() — there is an object before the dot, so this = user.
Read the steps as text
- user.hello() — there is an object before the dot, so this = user.
- const hello = user.hello copies only the function. The link to user is not copied.
- hello() — no object before the dot. In strict code, this = undefined, and reading this.name throws.
- hello.call(ravi) — you choose this explicitly.
- new Person('Mei') — new makes a fresh object and passes it as this.
Predict#
Predict first
const bound = hello.bind({ name: 'A' }); const obj = { name: 'B', bound }; What does obj.bound() return?
bind creates a function whose this is fixed, so calling it as a method cannot change it. Explicit binding beats implicit binding. Only new can override a bound this.
Interview angle#
Say it like this — about 30 seconds
“
thisis set by how a function is called. Withnew, it is the new object. Withcall,applyorbind, it is the value you pass. As a method,obj.fn(), it isobj. Otherwise it isundefinedin strict code or the global object in sloppy code. That is also the precedence order. Arrow functions are the exception: they takethisfrom the surrounding scope. Passing a method as a callback losesthisbecause only the function is passed.”
Follow-up What is the difference between call, apply and bind?
call and apply call the function now — call takes arguments one by one, apply takes an array. bind returns a new function with this (and optionally some arguments) fixed.Follow-up Why does const f = obj.method; f() lose this?
Follow-up How would you fix a method passed as a callback?
obj.method.bind(obj), wrap it in an arrow — () => obj.method() — or define the method as an arrow class field (JS.03.02).Practice#
On your own
Write bindAll(obj, ...names): replace each named method on obj with a version whose this is always obj.
Done when
- A bound method still works when detached:
const f = obj.m; f(). - Arguments pass through, and methods not named are left alone.
- It returns
obj.
Remember#
Try to answer each card before you open it. Then add them to your reviews.
What decides the value of this?
How the function is called, not where it is written.
List the this rules from strongest to weakest.
new, then explicit (call/apply/bind), then method call, then default.
What is this in a plain call in strict code?
undefined.
Why does passing obj.method as a callback lose this?
Only the function is passed; it is later called without an object before the dot.
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
Look at the call site. Something before the dot? That object is this. new? A new object. call/apply/bind? The value given. Nothing? undefined (strict).
Check yourself: In obj.a.b.fn(), what is this?
obj.a.b — the object directly before the last dot.
How it works underneathSenior rounds
obj.fn evaluates to a Reference Record that remembers its base, obj; calling it passes that base as thisValue Source: ECMA-262: EvaluateCall. Assigning to a variable reads only the function value, so the base is lost. In sloppy functions, an undefined this is replaced by the global object Source: ECMA-262: OrdinaryCallBindThis.
Check yourself: What spec value carries the object before the dot to the call?
A Reference Record, whose base value becomes thisValue.
Edge cases and trapsWhere people slip
Event listeners written as normal functions get the element as this. Normal-function callbacks to setTimeout in browsers get the global object as this, even in strict code, because the HTML Standard passes it. (0, obj.fn)() and (obj.fn = obj.fn)() lose this, but (obj.fn)() keeps it — parentheses alone do not change the reference.
Check yourself: What is this inside a DOM event listener written as a normal function?
The element the listener is attached to (event.currentTarget).
In productionStaff-level answers
Older React class components bound handlers in the constructor or used arrow class fields — both fixes for this exact problem. Libraries such as Lodash have bindAll. In modern code, prefer arrows and closures; reserve this for classes and methods.
Check yourself: Name two ways React class components kept this in handlers.
Binding in the constructor, or arrow-function class fields.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- How is
thisdetermined in JavaScript? List the rules in order of precedence. - What is the difference between
call,applyandbind? - Why does
const f = obj.method; f()losethis?