Classes are the standard way to model stateful objects and are used throughout the DOM and Node APIs.
A class bundles a constructor and methods for creating objects of the same shape:
class Account {
#balance = 0; // private field
static count = 0; // shared by the class
constructor(owner) { this.owner = owner; Account.count++; }
deposit(amount) { this.#balance += amount; return this; }
get balance() { return this.#balance; }
}The pieces:
constructorruns onnew Account("Ada")and initialises the instance.- Methods are shared by all instances.
- Fields (
name = value;) are created per instance before the constructor body runs. - Private members start with
#and are inaccessible outside the class body — truly private, not a naming convention.#field in objchecks whether an object has one. - Getters/setters (
get balance()) look like properties to callers. - `static` members belong to the class itself:
Account.count, factory methods likeAccount.fromJSON(). Astatic { }block runs once for class setup.
Inheritance uses extends. A subclass constructor must call super(...) before it touches this; methods can call super.method() to extend the parent's behaviour. instanceof checks the chain: savings instanceof Account.
Classes are mostly syntax over prototypes (covered later), with differences: class bodies are always strict, classes can't be called without new, and class declarations are in the TDZ until defined (not hoisted like functions).
Prefer composition over deep hierarchies: one level of extends is common, three is a smell. And not everything needs a class — plain objects and functions are often simpler.
Example
class Account {
#balance = 0;
static count = 0;
constructor(owner) {
this.owner = owner;
Account.count++;
}
deposit(amount) {
if (amount <= 0) throw new RangeError("amount must be positive");
this.#balance += amount;
return this; // allow chaining
}
get balance() { return this.#balance; }
}
class Savings extends Account {
constructor(owner, rate) {
super(owner); // must come before using this
this.rate = rate;
}
addInterest() { return this.deposit(this.balance * this.rate); }
}
const s = new Savings("Ada", 0.05).deposit(100);
s.addInterest();
console.log(s.balance, s instanceof Account, Account.count); // 105 true 1
// s.#balance -> SyntaxError outside the classRemember
- Fields and
#privatemembers are declared in the class body extends+super()for inheritance; callsuperbefore usingthisstaticmembers live on the class; getters make computed properties
Watch out for
- Forgetting
super()in a subclass constructor (ReferenceError whenthisis used).