Day 4 · Concept 12
Classes
ES6 classes are syntactic sugar over the prototype system. Cleaner than the old function Foo() {...} + Foo.prototype.bar = ... dance. Still need to understand prototypes for debugging.
1 · The basics
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `hi, ${this.name}`;
}
// Static — on the class, not instances
static fromObject({ name, age }) {
return new User(name, age);
}
}
const u = new User("Alice", 30);
console.log(u.greet());
const u2 = User.fromObject({ name: "Bob", age: 25 });
console.log(u2.greet());2 · Inheritance with extends
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks`; }
fetch() { return `${this.name} fetches`; }
}
const d = new Dog("Rex");
console.log(d.speak());
console.log(d.fetch());
// super calls the parent
class Cat extends Animal {
speak() { return super.speak() + " (meow)"; }
}
console.log(new Cat("Whiskers").speak());3 · Private fields and getters/setters
class Counter {
#count = 0; // # = private, not accessible outside the class
get value() { return this.#count; }
increment() { this.#count += 1; }
set value(n) {
if (n < 0) throw new Error("must be >= 0");
this.#count = n;
}
}
const c = new Counter();
c.increment();
c.increment();
c.value = 10;
console.log(c.value);
// c.#count; // SyntaxError outside the class4 · Class fields and arrow methods
class Button {
label = "Click";
clickCount = 0;
// Arrow as class field — bound to the instance automatically
onClick = () => {
this.clickCount += 1;
console.log(`${this.label}: ${this.clickCount}`);
};
}
const b = new Button();
const handler = b.onClick; // detach
handler(); // still works — bound
handler();Useful in React class components for event handlers — but classes themselves are uncommon in modern React (function components dominate).
5 · Classes vs factory functions
| Class | Factory function |
|---|---|
| Familiar syntax for OOP coming from Java/C# | No new, no this, simpler |
instanceof works | Not directly |
| Prototype chain — extension possible | No inheritance chain |
| Better tooling (inspectors show class) | Lighter, no new mistakes |
Modern JS frequently uses factories for data objects and classes for things with state + behaviour (parsers, services, frameworks).
6 · Common mistakes
- Forgetting
new.User("x")withoutnewthrows. - Class methods losing
thiswhen detached. Use arrow class fields or bind in the constructor. - Mutating shared prototype properties. Class methods are on the prototype — mutating
User.prototype.fooaffects all instances.
7 · When it clicks
- You pick class vs factory based on whether you need
extendsorinstanceof. - Private fields with
#are reflex when you want true encapsulation. - You recognise classes are sugar — and can debug the prototype chain when needed.
Found this useful?