Why use an arrow function as a method?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
Because this is then fixed to the instance and cannot be lost, which matters the moment you pass the method somewhere else.
A normal method loses its this when detached from the object:
class Counter {
count = 0;
incrementNormal() { this.count++; }
incrementArrow = () => { this.count++; };
}
const c = new Counter();
const a = c.incrementNormal;
const b = c.incrementArrow;
a(); // TypeError — `this` is undefined
b(); // works
This is why the arrow form is common for event handlers and callbacks:
button.addEventListener("click", c.incrementArrow); // fine
button.addEventListener("click", c.incrementNormal); // broken
button.addEventListener("click", () => c.incrementNormal()); // also fine
How it works
An arrow class field is not on the prototype. It is created per instance in the constructor, closing over that instance's this. Nothing can rebind it — call, apply and bind are all ignored.
The costs
- One function per instance, not one shared on the prototype. With a handful of objects this is irrelevant; with thousands it is real memory.
- Not on the prototype, so a subclass cannot override it with
super.method(), and it will not appear where prototype methods are expected. - Harder to stub in tests for the same reason.
When to choose which
Use a normal method by default. Reach for an arrow field when the method is passed as a callback and you want that guarantee built in. The alternatives — binding in the constructor, or wrapping in an inline arrow at the call site — achieve the same thing; the field version just puts the decision next to the definition instead of every use.
Note this only applies to arrow functions as class fields. An arrow as an object literal method is usually a mistake: it takes this from the enclosing scope, not the object.
