Skip to content
Intermediate11 min study

The this keyword

Resolve this from the call site across constructor, explicit, implicit, default, bound, and lexical arrow-function behavior.

Question progress0 / 10 completed
Start the lesson
The this keyword visual explanation

WHAT YOU WILL BE ABLE TO DO

Learning outcomes

  • Explain the this keyword in plain language.
  • Connect the behavior to the underlying browser or framework model.
  • Implement the core pattern and reason through edge cases.
  • Answer common follow-ups without relying on memorized phrases.

01Overview

this is not determined by where a function is defined; it's determined by how the function is called — the call site.

02Mental model

  • new binding: calling with new makes this the newly created object (highest precedence).
  • Explicit binding: call, apply, or bind set this directly.
  • Implicit binding: obj.method() sets this to obj.
  • Default binding: a bare function call gets this as undefined (strict mode) or the global object.
  • Arrow functions ignore all of the above and use this from their enclosing lexical scope.
Think of it like this: this is less like a fixed label glued to a function, and more like a walkie-talkie channel that gets assigned fresh the moment someone actually keys the mic — it depends entirely on how the call happens, not where the function was written.

03Examples

JavaScript
const user = {  name: 'Ada',  greet() { return `Hi, ${this.name}`; },};const greet = user.greet;greet(); // this is undefined/global — 'name' lookup fails
const bound = user.greet.bind(user);bound(); // 'Hi, Ada'

04Check understanding

Why does extracting a method and calling it standalone break this?

Extraction discards the call-site: obj.method() implicitly binds this to obj, but a bare reference invoked alone falls back to default binding.

How to say it out loud: "this isn't determined by where a function is defined — it's determined by how the function is actually called, the call site. There's a precedence order: calling with new gives the highest priority and makes this the newly created object; explicit binding with call, apply, or bind sets it directly; calling as a method like obj.method() implicitly binds this to obj; and a bare function call falls back to undefined in strict mode. Arrow functions break this pattern entirely — they don't get their own this at all, they just inherit it from whatever scope they were defined in. That's exactly why extracting a method off an object and calling it standalone breaks — const fn = obj.method; fn() loses the implicit binding that obj.method() had, because the call site changed."

DDConcept deep dives

Deep dive 1

Ordinary-function this comes from the call expression

Look at how the function is invoked, not where its source appears. A constructor call creates a new receiver; call, apply, or bind supplies one explicitly; a member call supplies its base object; a plain strict-mode call supplies undefined. These rules have precedence, and losing the member call by extracting a method loses its implicit receiver.

  • obj.method() and const m = obj.method; m() are different call forms.
  • Callback APIs decide how they invoke an ordinary function.
  • Destructuring a method does not preserve its original object.

Deep dive 2

Arrow functions inherit this

An arrow does not define its own this, arguments, super, or new.target bindings. It resolves them from the surrounding lexical environment. That makes it convenient inside a method callback that should retain the method's receiver, but it also means call, apply, and bind cannot provide a different receiver and the arrow cannot be used as a constructor.

  • A class-field arrow creates a new function for each instance.
  • An arrow used as an object-literal method usually captures an outer this, not the object.
  • Lexical this removes call-site flexibility intentionally.

Deep dive 3

API design can remove receiver ambiguity

Dynamic this is useful when behavior is intentionally shared across receivers, as with prototype methods. For many utilities, an explicit object parameter or closure makes dependencies clearer. In UI callbacks, binding once produces stable identity for registration and removal; creating bind or an inline wrapper at both boundaries produces different functions and cleanup fails.

  • Choose receiver-based methods when object identity is part of the abstraction.
  • Prefer explicit dependencies for pure transformation logic.
  • Retain the exact callback reference required by removeEventListener.

QAInterview questions and model answers

Attempt each answer aloud before opening it. The model answer shows the depth and precision expected in an interview; it is not a script to memorize.

Intermediate · Coding · 1 min · Question 1How is this determined in JavaScript?Open model answer

Model answer

For ordinary functions, this is determined by the call form: new binding, explicit call/apply/bind, method-style implicit binding, or the default rule. Arrow functions do not create their own this; they resolve it lexically from the surrounding scope.

JavaScript
function whoAmI() { return this; }
whoAmI();                 // undefined (strict) or global (sloppy) — defaultwhoAmI.call({ id: 1 });   // { id: 1 } — explicitconst o = { whoAmI };o.whoAmI();               // o — implicit (method call)new whoAmI();             // the new instance — new binding
Open question page →
Intermediate · Coding · 1 min · Question 2Why does const f = object.method; f() lose the object?Open model answer

Model answer

The reference is extracted and then called as a plain function, so the member-call base object is no longer part of the call expression. Bind the method, wrap it in another function, or design the API so it does not depend on dynamic this.

JavaScript
const user = { name: 'Ada', greet() { return `Hi ${this.name}`; } };
const g = user.greet;g();                       // "Hi undefined" — call site has no base objectconst bound = user.greet.bind(user);bound();                   // "Hi Ada"
Open question page →
Intermediate · Conceptual · 1 min · Question 3What does bind return?Open model answer

Model answer

bind creates a new function with permanently associated this and optional leading arguments. Calling it with call or apply cannot replace the bound this. When invoked with new, constructor semantics take precedence for the created instance.

Open question page →
Intermediate · Coding · 1 min · Question 4How does this behave in arrow functions?Open model answer

Model answer

An arrow captures this from its lexical environment and ignores call, apply, and bind attempts to replace it. That makes arrows useful for callbacks needing the enclosing instance, but unsuitable as dynamically bound object methods or constructors.

JavaScript
const timer = {  seconds: 0,  start() {    setInterval(() => { this.seconds++; }, 1000); // arrow: `this` is `timer`  },};// A regular function here would get its own `this` (undefined/global).
Open question page →
Intermediate · Conceptual · 1 min · Question 5What is default this in strict mode?Open model answer

Model answer

A plain call to an ordinary strict-mode function receives undefined. In sloppy mode it may substitute the global object and box primitives. ES modules and class bodies use strict semantics, so relying on sloppy default binding is fragile.

Open question page →
Intermediate · Conceptual · 1 min · Question 6Does this point to the function that is running?Open model answer

Model answer

No. this is a call-time value, not a pointer to the current function or necessarily the object where the function was defined. Lexical arrows are the exception in the sense that they inherit the surrounding this.

Open question page →
Advanced · Conceptual · 1 min · Question 7How does new interact with an explicitly returned object?Open model answer

Model answer

If a constructor explicitly returns an object, that object replaces the newly created receiver. Returning a primitive does not replace the constructed instance.

Open question page →
Intermediate · Conceptual · 1 min · Question 8What is this inside a class static method?Open model answer

Model answer

A static method is called on the class constructor, so an ordinary member call binds this to that constructor or the subclass used as the receiver.

Open question page →
Beginner · Conceptual · 1 min · Question 9Can an arrow function be used with new?Open model answer

Model answer

No. Arrow functions lack [[Construct]] and their own prototype property for instance construction, so calling one with new throws a TypeError.

Open question page →
Advanced · Conceptual · 1 min · Question 10How does super relate to this in a derived constructor?Open model answer

Model answer

A derived constructor cannot access this before calling super. super initializes the inherited instance receiver, after which the constructor may use this.

Open question page →

SCScenario questions

Scenario 1

A class method passed directly as a click callback crashes because this is undefined. Compare fixes.

  1. Identify the lost receiver at the callback boundary.
  2. Consider binding once in construction, a class-field arrow, or a wrapper at registration.
  3. Ensure removal uses the same function identity.
  4. Question whether the method needs this at all.
Reveal worked answer

Binding once preserves a stable callback identity but creates one bound function per instance. A class-field arrow also creates per-instance state and lexical this. An inline wrapper is simple but must be retained if removal is required. A pure function receiving explicit data avoids this coupling entirely.

Verify and go deeper