Back to JavaScript
JavaScript
medium
mid

How do you preserve an object's context when calling a function later in JavaScript?

When you detach a method (pass it as a callback), `this` is lost. Preserve it with: .bind(obj) to create a permanently-bound function, an arrow wrapper () => obj.method() that calls it as a method, or arrow class fields. bind is the canonical tool; arrow wrappers are common in callbacks/JSX.

4 min read·~8 min to think through

The problem: this is determined by how a function is called, not where it's defined. Detach a method from its object and call it later, and this is lost:

js
const obj = {
  name: "Ada",
  greet() { return `Hi, ${this.name}`; },
};

const fn = obj.greet;
fn(); // ❌ this is undefined (strict) — "Hi, undefined"

setTimeout(obj.greet, 100);  // ❌ same — called bare later
button.addEventListener("click", obj.greet); // ❌ this becomes the button

The fixes — ways to lock this to the object:

1. .bind() — the canonical tool

js
const bound = obj.greet.bind(obj);
bound();                      // ✅ "Hi, Ada" — this permanently bound
setTimeout(obj.greet.bind(obj), 100);  // ✅

.bind(thisArg) returns a new function with this permanently set — it can't be re-bound. The standard, explicit solution.

2. Arrow function wrapper

js
setTimeout(() => obj.greet(), 100);            // ✅
button.addEventListener("click", () => obj.greet()); // ✅

You're not binding — you're calling obj.greet() as a method (with obj. at the call site) inside the arrow. The arrow itself just defers the call. Very common in callbacks and JSX event handlers.

3. Arrow function as a class field

js
class Greeter {
  name = "Ada";
  greet = () => `Hi, ${this.name}`;   // arrow field captures the instance's this
}
const g = new Greeter();
const fn = g.greet;
fn(); // ✅ "Hi, Ada"

The arrow class field captures this lexically at construction, so it survives detachment. Common in React class components (avoids binding handlers in the constructor).

4. call / apply — for immediate calls

fn.call(obj) / fn.apply(obj) invoke immediately with a given this — but they don't help for "call later," which is the question. bind is the "later" version.

When you hit this

Passing methods as callbackssetTimeout, addEventListener, .map(), array methods, React event handlers, promise .then(). The fix is bind or an arrow wrapper.

The framing

"this is set by how a function is called, so detaching a method and calling it later loses it. To preserve it: .bind(obj) returns a new function with this permanently locked — the canonical, explicit fix. An arrow wrapper () => obj.method() works differently — it defers a method call, keeping obj. at the call site. And an arrow class field captures the instance's this lexically so it survives detachment — common in React class components. call/apply set this but only for an immediate call, not for 'later.'"

Follow-up questions

  • What's the difference between bind and an arrow wrapper?
  • Why does an arrow class field preserve `this`?
  • Can you re-bind a function that's already bound?
  • Why don't call/apply solve the 'call later' case?

Common mistakes

  • Passing obj.method directly as a callback and losing this.
  • Thinking call/apply help for deferred calls (they're immediate).
  • Trying to re-bind an already-bound function.
  • Using a regular function where an arrow's lexical this was needed.

Performance considerations

  • bind and arrow wrappers create a new function each time — in React, creating them inline in render can defeat memoization of child components; stabilize with useCallback or class fields when it matters.

Edge cases

  • Double-binding — the first bind wins.
  • bind also pre-fills arguments (partial application).
  • Arrow functions ignore bind/call/apply for `this`.
  • Event handler needing both `this` and the event object.

Real-world examples

  • Binding event handlers in React class components (or using arrow class fields).
  • Passing a method to setTimeout/addEventListener with .bind or an arrow wrapper.

Senior engineer discussion

Seniors explain `this` is call-site-determined, give bind as the canonical fix, distinguish it from the defer-a-method-call arrow wrapper, cover arrow class fields, and note call/apply are for immediate invocation — plus the new-function-per-render perf caveat.

Related questions