Topics in this subject
JavaScript 2 min read Updated 4 Aug 2026

Part 19 — Object-Oriented JavaScript

Static, private, and checks, Composition vs inheritance & mixins 🎯, SOLID in JS (pragmatic)

Classes are syntactic sugar over prototypes (Part 10). Under the hood, methods live on Class.prototype.

class Animal {
  static count = 0;                  // static field (on the class)
  #energy = 100;                     // private field (truly private) 🟢

  constructor(name) {
    this.name = name;                // public instance field
    Animal.count++;
  }
  speak() { return `${this.name} speaks`; }   // on prototype
  get energy() { return this.#energy; }        // getter
  set energy(v) { this.#energy = Math.max(0, v); }
  #recover() { this.#energy += 10; }           // private method
  static create(name) { return new Animal(name); } // static method
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);                     // must call before using `this`
    this.breed = breed;
  }
  speak() { return `${super.speak()} — woof`; } // override + super
}

const d = new Dog("Rex", "Lab");
d.speak();          // "Rex speaks — woof"
d instanceof Animal;// true
Animal.count;       // 1
// d.#energy         // ❌ SyntaxError — private, inaccessible outside

Static, private, and checks#

  • static members belong to the class, not instances.
  • #field / #method() are hard private — enforced by the engine (unlike _name convention).
  • #x in obj 🟢 (ES2022) is the brand check for private fields.

Composition vs inheritance & mixins 🎯#

Prefer composition ("has-a") over deep inheritance ("is-a"). Deep hierarchies are rigid and fragile.

// mixin — share behaviour without inheritance
const Serializable = (Base) => class extends Base {
  toJSON() { return JSON.stringify({ ...this }); }
};
class User {}
class SerializableUser extends Serializable(User) {}

SOLID in JS (pragmatic)#

  • Single Responsibility — a module/class does one thing.
  • Open/Closed — extend behaviour without editing existing code (strategy pattern, plugins).
  • Liskov — subtypes must be usable wherever the base is.
  • Interface Segregation — small focused interfaces (in JS, small focused objects/functions).
  • Dependency Inversion — depend on abstractions; inject dependencies rather than hard-coding them.

Interview questions (Part 19):

  1. Are JS classes "real" classes? What's underneath?
  2. #private vs _convention privacy — difference and enforcement.
  3. Composition vs inheritance — when to prefer each.
  4. What does super do and when must you call it?