CodePark/ questions / this in methods & callbacks
START PRACTICINGPRACTICE
Backend question · Object-oriented programming › this in methods & callbacks

Why does passing service.method as a callback lose this? Show three ways to fix it and say which you prefer.

In JavaScript, this is decided by how a function is called, not where it was written. service.list() sets this to service. But const fn = service.list copies only the function. When the router or a timer later calls fn(), there is no object before the dot. In a class (always strict mode) this is undefined.

Three fixes:

  • Arrow wrapper at the call site: app.get("/users", (req, res) => service.list(req, res)). Clear and local. My default.
  • Bind once in the constructor: this.list = this.list.bind(this). Every caller is safe, but it is easy to forget for new methods.
  • Arrow class field: list = (req, res) => { ... }. Always bound, but it is created per instance, is not on the prototype, and can't be called with super.

The same bug appears with setTimeout(this.flush, 1000), items.map(this.format) and event listeners. Frameworks like NestJS avoid it, because they call your methods on the instance themselves.

  • this is set by the call site, not by where the method is defined.
  • Passing service.method detaches the function from its object.
  • Class code is strict, so a detached call gets this === undefined.
  • Fixes are an arrow wrapper, bind in the constructor, or an arrow class field.
  • Each fix has trade-offs, and an arrow wrapper at the call site is the most explicit.