learn
JavaScript

The this keyword

The four rules, arrows, and call, apply and bind.

this is decided by the call, not the definition — which is why the same method works on its object and breaks the moment you pass it as a callback. Interviewers ask this because "lost context" bugs hide in every event handler and timer.

Real-life situation

A login form object has a greeting method using this.user. Called as loginForm.greeting(), it works. Handed to a button as a callback, the dot is gone, this is no longer the form, and the greeting shows undefined. Binding once at handoff — or wrapping in an arrow — keeps the receiver.

Seen in: React class components bind handlers in the constructor for exactly this reason (React 16, 2017, Component reference).

Visual

This rules
BrowserAPIRealtimeCacheDatabaseShareddurableephemeral

Try it

Losing the dot
javascriptTab moves to the next control
const loginForm = {
user: "ada",
greeting: function () {
  return "hi " + this.user;
},
};
console.log(loginForm.greeting());
const loose = loginForm.greeting;
console.log(loose());
const bound = loginForm.greeting.bind(loginForm);
console.log(bound());
function welcome(city) {
return this.user + " from " + city;
}
console.log(welcome.call(loginForm, "Lagos"));
console.log(welcome.apply(loginForm, ["Abuja"]));
Press Run to see the output.
Expected output
hi ada
hi undefined
hi ada
ada from Lagos
ada from Abuja
Runner helpers

sleep(ms) waits; fakeFetch(url) returns deterministic sample data. Console code runs in a worker with a 5-second limit.

Try wrapping the callback as function () { return loginForm.greeting(); } instead of binding. Then try welcome.call(null, "Lagos") and explain it.

When to bind, when to arrow

Bind (or wrap) at handoff: listeners, timers, array callbacks. Arrow for callbacks written inside methods that must keep the outer this. Never bind an arrow — it has no this to set.

Detached method — guess first, then reveal.

predict.js
const inbox = {
user: "meera",
read: function () {
  return "hi " + this.user;
},
};
const later = inbox.read;
console.log(later());

Interview questions

What decides the value of this in a function?basic

The call site, not the definition site. The same function can see a different this depending on how it is invoked — as a method, as a bare call, or bound in advance. That single rule explains nearly every this surprise: when context is lost, something changed how the function was called, usually by passing it as a callback.

Interviewers also ask

  • How do arrow functions break this rule?
What are the four rules of this?basic

New binding: new points this at the fresh object. Explicit: call, apply or bind set it directly. Implicit: calling as user.save() sets it to user. Default: a bare call gets undefined in strict mode (the global object in sloppy mode). When rules collide, new beats explicit beats implicit beats default — memorize that order and most puzzles solve themselves.

Interviewers also ask

  • What happens when several rules apply at once?
Why does this become undefined inside a callback like setTimeout?basic

Because passing user.save as a callback separates the function from its object — setTimeout later invokes it as a bare function, so the implicit rule no longer applies and strict mode gives undefined. Fixes: wrap it (() => user.save()), which preserves the method-call form, or bind it once (user.save.bind(user)). Losing the dot is losing the receiver.

Interviewers also ask

  • Which fix would you use in an event handler?
How do arrow functions treat this?intermediate

They don't have one. An arrow inherits this from the surrounding scope where it is written, permanently — call and bind cannot change it. That makes arrows ideal for callbacks inside methods (the handler keeps the component) and wrong for object methods or prototype functions that need a dynamic receiver. If this must vary per call, write function.

Interviewers also ask

  • Can bind change an arrow's this?
What does bind return, and when do you reach for it?intermediate

bind returns a NEW function with this (and optionally leading arguments) locked in; the original is untouched and nothing runs yet. Reach for it when handing a method to someone else: event listeners, timers, array callbacks, promises. One bind at handoff beats debugging a mystery undefined three stack frames later.

Interviewers also ask

  • How is bind different from call?
What is this inside a class, and where does it break?intermediate

In class methods this is the instance — until the method is detached. A button.onclick = panel.save or setTimeout(panel.save) call loses the receiver exactly like plain objects do. The standard fixes are binding in the constructor, binding at handoff, or defining the handler as an arrow field (which closes over the instance). Frameworks hit this constantly, which is why the pattern is worth naming.

Interviewers also ask

  • Why do arrow-function class fields avoid the problem?
What is this in strict mode versus sloppy mode for a bare call?basic

A bare call like save() gets undefined in strict mode and the global object (window/globalThis) otherwise. Strict mode's undefined fails fast and loud; sloppy mode silently reads and writes globals, hiding bugs. Modules are always strict, so modern code sees undefined — treat a surprise undefined this as a detached-method bug until proven otherwise.

Interviewers also ask

  • Are ES modules strict by default?
How does new set this, step by step?intermediate

new Cart() creates a fresh empty object, links it to Cart.prototype, runs the constructor with this pointing at that object, and returns it (unless the constructor returns its own object). Forgetting new runs the same function as a bare call — this is undefined in strict mode and the constructor's assignments throw instead of building anything.

Interviewers also ask

  • What happens if you forget new?
Why do DOM event handlers get the element as this?intermediate

Because the browser invokes the listener as a method of the element — the implicit rule again, with the element as receiver. Add the same listener via an arrow wrapper and this becomes whatever surrounded the arrow, which is why handler code mixing styles confuses readers. Modern handlers usually ignore this entirely and use the event object (event.target) instead — say so if the interviewer probes.

Interviewers also ask

  • Should new code rely on handler this?
Give a one-line rule for predicting this.basic

Look at the call, not the function: obj.fn() means obj, bare fn() means undefined (strict), fn.call(x) means x, new Fn() means the new object, and arrows mean "whatever surrounded me". Say that sentence in the interview, then apply it line by line — it resolves nearly every textbook puzzle out loud.

Key takeaways

  • this comes from the call: method, bare call, explicit set, or new.
  • Losing the dot loses the receiver — bind or wrap at handoff.
  • Arrows inherit this and ignore call, apply and bind.

References

Last verified: 2026-10-12.

On this page