JavaScript · Core language
`this` binding (4 rules)
⚡ TL;DR —
thisis neither lexical nor "the function" — it's decided at call time by how the function is called. Four rules, in priority order:new> explicit (call/apply/bind) > implicit (method call) > default. Arrow functions opt out of all four and inheritthislexically.
🧠 Mental model
Stop asking "where is this function defined?" Ask "how was it called?" this is effectively an implicit parameter passed at the call site. The thing to the left of the dot, or the new, or the .call(...), is what sets it. Move the same function to a different call site and this changes — that's the whole idea, and the source of every surprise.
⚙️ How it actually works
The engine resolves this by checking, in this priority:
new Foo()→thisis a brand-new object linked toFoo.prototype.- Explicit:
fn.call(o),fn.apply(o), or afn.bind(o)result →thisiso. - Implicit:
obj.fn()→thisisobj(the receiver, left of the dot). - Default: a bare
fn()→undefinedin strict mode,globalThisin sloppy mode.
The failure mode is losing the dot: const f = obj.method; f() drops the receiver, so rule 4 applies and this is undefined. That's why passing a method as a callback "loses this". Arrow functions sidestep the entire table — they have no this binding and resolve this from the enclosing lexical scope, which cannot be overridden by call, bind, or even new.
💻 Code
const user = {
name: 'Ada',
greet() { return `Hi ${this.name}`; },
};
user.greet(); // 'Hi Ada' — implicit: receiver is `user`
const g = user.greet;
g(); // 💥 undefined.name — dot gone → default binding
g.call(user); // 'Hi Ada' — explicit binding
setTimeout(user.greet, 0); // 💥 detached — passed without the receiver
// Arrow inherits `this` lexically → survives detachment
const timer = {
label: 'tick',
start() {
setTimeout(() => console.log(this.label), 0); // 'tick' — `this` is `timer`
},
};
// `new` wins over implicit; even wins over bind (keeps bound args, not `this`)
function Point(x) { this.x = x; } // `this` = fresh instance
const p = new Point(5); // p.x === 5
⚖️ Trade-offs
- Arrows for callbacks and class fields; regular functions for methods. Arrows give you stable lexical
this(perfect insidemap,setTimeout, event handlers you close over). Regular functions give you dynamicthis— exactly what prototype methods and DOM handlers want. - Never use an arrow as an object method if you need
thisto be that object — it'll capture module/global scope instead. - Never use an arrow as a constructor — no
this, noprototype;newthrows.
💣 Gotchas interviewers probe
thisis call-time, not definition-time. The most repeated mistake. Same function, different call site, differentthis.- Detached methods lose
this.arr.forEach(obj.method)breaks; usearr.forEach(obj.method.bind(obj))or an arrow wrapper. - Arrow functions can't be rebound.
arrow.call(x)/arrow.bind(x)are no-ops forthis; as a DOM handler,thisis not the element. - Sloppy vs strict default. Bare-call
thisisglobalThisin sloppy mode,undefinedin strict. Modules and class bodies are always strict — a big source of "it worked in the console but not in my module". - Nested plain function inside a method gets the default binding, not the outer object. Pre-arrow, people wrote
const self = this. - Top-level
thisisundefinedin ES modules,globalThis/module.exportselsewhere.
🎯 Say this in the interview
"
thisisn't lexical and it isn't the function — it's set at the call site by how you call the function. I resolve it with four rules in priority order:newcreates and binds a fresh object;call/apply/bindset it explicitly; a method call binds it to the receiver left of the dot; and a bare call falls back toundefinedin strict mode or the global object in sloppy mode. The classic bug is losing the dot — assigningobj.methodto a variable or passing it as a callback drops the receiver, sothisbecomesundefined. Arrow functions are the exception: they have nothisof their own and inherit it lexically, which is exactly why they're the right tool inside callbacks and the wrong tool as object methods or constructors."
🔗 Go deeper
- javascript.info — Object methods, "this" — the four call patterns with clear examples.
- MDN —
this— the exhaustive spec-accurate reference, including strict-mode and arrow behaviour. - javascript.info — Arrow functions revisited — why arrows have no
thisand when that matters.