Some functions clearly belong to a model without belonging to any particular object: converting a unit, validating an input before construction, counting the instances created. Storing them in an ordinary method would force you to build an object for nothing.
static resolves that mismatch by attaching the member to the class itself.
Definition
static comes before a method, a field or an accessor in the body of a class. The resulting member is called on the class, never on an instance, and takes no part in the state of the objects created.
class Temperature {
static ABSOLUTE_ZERO = -273.15;
constructor(celsius) {
this.celsius = celsius;
}
static fromFahrenheit(degrees) {
return new Temperature((degrees - 32) / 1.8);
}
}
console.log(Temperature.ABSOLUTE_ZERO); // -273.15
console.log(Temperature.fromFahrenheit(212).celsius); // 100
const reading = new Temperature(20);
console.log(reading.fromFahrenheit); // undefinedThe last line often surprises people: a static member does not exist on instances. It is not hidden, it is simply not there, and an attempt to call it raises a type error.
Static or instance, how to choose
| Criterion | Static member | Instance member |
|---|---|---|
| Called on | The class | An object created with new |
| Value of this | The class itself | The current object |
| Access to object data | None | Complete |
| Typical use | Constant, factory, helper | Behavior of an object |
The decision rule fits in one question: does the function need the data of a particular object. If the answer is no, a static member says exactly that to the reader, and spares an object created for no reason.
State shared by the whole class
The other common use is data that belongs to the model rather than to the objects: a counter, a cache, a limit. An instance field would not do, since each object would keep its own copy.
class Ticket {
static #counter = 0;
constructor() {
Ticket.#counter += 1;
this.number = Ticket.#counter;
}
static howMany() { return Ticket.#counter; }
}
new Ticket();
new Ticket();
console.log(Ticket.howMany()); // 2The private static field acts here as a counter shared by every instance and unreachable from outside. Each object reads and increments a single value, something no instance field could ever do.
A static member is inherited: a class using extends can call the static methods of its parent on itself. That is what lets a factory declared at the top of the hierarchy serve the whole line of descendants.
Frequently asked questions
How does it differ from a plain exported function?
Technically very little: both do the same work. A static method wins when the function only makes sense alongside the class, because it stays next to the model and reads with it. An independent function wins when it serves elsewhere, and can then be published with export without dragging a whole class behind it.
What is this worth inside a static method?
It means the class the call was made on, not an instance. That detail matters with inheritance: if a child class calls a factory declared in the parent, this means the child, so a construction written with that keyword really does produce an instance of the child.
Can a static constant be declared?
A static field serves that purpose, like the absolute zero above, but nothing stops anyone from overwriting it from outside. For real protection, declare the field private with a hash and expose it through a read-only static accessor. The const keyword itself cannot be used inside a class body.