Arrow methods vs regular methods
A regular class method is stored on the prototype and receives this dynamically, at call time, while an arrow method is an instance field that captures this when the object is created and never loses it. The syntactic difference is tiny, but the consequences for memory, inheritance and callback behaviour are radically different.
Theory
TL;DR
- A regular method lives in
Class.prototypeand is shared by all instances. - An arrow method is an own property of the instance, a new function for every
new. - A regular method resolves
thisat call time, an arrow method has it fixed forever. - An arrow method does not lose its context in
setTimeoutoraddEventListener, a regular one does withoutbind. superworks only with regular methods; an arrow field has no access to it.- Arrow methods are enumerable and appear in
Object.keys(), regular ones do not.
Quick example
class User {
name = "Maria";
normal() {
console.log("normal:", this.name);
}
arrow = () => {
console.log("arrow:", this.name);
};
}
const u = new User();
setTimeout(u.normal, 500); // TypeError: Cannot read properties of undefined
setTimeout(u.arrow, 500); // arrow: Marianormal() lost its context because it was called as an ordinary function. arrow() kept the context because an arrow function has no this of its own, it captures this from the instance while the field is being initialised.
Syntax
A regular method:
class Button {
handleClick() {
console.log(this.label);
}
}An arrow method (a method field):
class Button {
handleClick = () => {
console.log(this.label);
};
}At first sight the only difference is = () => {}, but the behaviour is fundamentally different.
The main difference: how this behaves
| Method type | How this works |
|---|---|
| Regular method | this is decided at call time (dynamically) |
| Arrow method | this is hard bound to the instance when the object is created |
That is exactly why in the example above the regular method throws while the arrow one prints the name.
Where methods are stored
| Method type | Where it is stored | Shared by all instances? |
|---|---|---|
| Regular | In ClassName.prototype | Yes |
| Arrow | In the instance itself (on every object) | No |
class A {
normal() {}
arrow = () => {};
}
const a1 = new A();
const a2 = new A();
console.log(a1.normal === a2.normal); // true, one method on the prototype
console.log(a1.arrow === a2.arrow); // false, each instance has its ownArrow methods are recreated on every new A(). This gives this its independence, but costs a little in memory and in object creation speed.
Event handlers and callbacks
A regular method loses this unless you bind it by hand:
class Button {
constructor() {
this.label = "Click me";
document.body.addEventListener("click", this.handleClick);
}
handleClick() {
console.log(this.label); // undefined, the context is lost
}
}Solution 1: bind it manually.
document.body.addEventListener("click", this.handleClick.bind(this));Solution 2 (more modern): use an arrow method.
class Button {
label = "Click me";
handleClick = () => {
console.log(this.label); // "Click me"
};
}Arrow methods fit React components and event handlers well, where it matters that this is not lost.
Inheritance and overriding
Regular methods are easy to override in subclasses, including through super:
class A {
greet() { console.log("Hello from A"); }
}
class B extends A {
greet() {
super.greet(); // works
console.log("Hello from B");
}
}With an arrow field this does not work:
class A {
greet = () => console.log("Hello from A");
}
class B extends A {
greet = () => {
super.greet(); // error, there is no super method to call
};
}The reason is that arrow methods are created on the instance, not on the prototype, so overriding is just overwriting a field, and the parent version simply is not in the prototype chain.
Difference in iteration and debugging
Regular methods are non-enumerable, so Object.keys() does not show them. Arrow methods are ordinary instance properties, so they are enumerable:
class Example {
method() {}
arrow = () => {};
}
const e = new Example();
console.log(Object.keys(e)); // ['arrow']This also means arrow fields are copied by spread and Object.assign, while prototype methods are not.
Performance
| Criterion | Regular method | Arrow method |
|---|---|---|
| Memory | 1 function for all | its own function per instance |
| Creation speed | Faster | Slower |
this context | Lost without bind | Always preserved |
Suitable for super | Yes | No |
| Suitable for callbacks | Needs bind | An ideal fit |
Summary comparison
| Feature | Regular method | Arrow method |
|---|---|---|
| Where it is stored | Class.prototype | In the instance |
| Shared by all | Yes | No |
this behaviour | Depends on the call | Fixed |
this lost in callbacks | Possible | No |
super support | Yes | No |
| Takes part in inheritance | Yes | No |
| Performance | Better | Slightly worse |
| Use in React and events | Inconvenient | Very convenient |
In short: use regular methods when the method is logically shared by all instances and may be overridden; use arrow methods when preserving this matters, for example when passing the method as a callback or an event handler.
Common mistakes
- Making every method an arrow just in case. That multiplies functions in memory and strips the class of normal inheritance.
- Expecting
superinside an arrow field. It is not there, because the field does not live on the prototype. - Being surprised that
Object.keys(instance)shows methods. It shows the arrow fields, because they are enumerable own properties. - Assuming a regular method will keep
thison its own. Withoutbindor an arrow wrapper it loses the context in any callback. - Confusing the initialisation order. Arrow fields are created while the instance is being constructed, so in a base class they are not yet available at the time its constructor runs in a subclass.
- Using arrow fields where the method must be mocked or replaced in tests through the prototype. Patching
Class.prototype.methodhas no effect on an arrow field.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.