class OrderController {
constructor(private service: OrderService) {}
list(req: Request, res: Response) { /* prototype method */ }
create = async (req: Request, res: Response) => { /* arrow field */ };
}
A prototype method like list is stored once on OrderController.prototype. All instances share it. An arrow-function field like create is a new function made for every instance in the constructor. It captures this from the instance, so it keeps working when you pass it as a callback.
Arrow field. Pros:
router.post("/", controller.create)works, becausethisis fixed.
Arrow field. Cons:
- One function per instance. This costs memory only when you create many instances.
- A subclass cannot call it with
super.create(), because it is not on the prototype. jest.spyOn(OrderController.prototype, "create")does not find it.
Rule of thumb: use prototype methods by default. Use an arrow field only for a method you really pass around as a callback, such as an event handler. Or keep methods normal and bind at the call site: router.post("/", (req, res) => controller.create(req, res)).
- A prototype method exists once and is shared by all instances.
- An arrow field is a new function on every instance, and it keeps
thisbound. - Arrow fields cannot be reached with
superand are not on the prototype for spies. - Default to prototype methods and use arrow fields only for real callbacks.