Inheritance in JavaScript

Introduction

Inheritance lets a child class reuse and extend a parent class. JavaScript uses prototype chains; extends and super express parent/child relationships clearly. This chapter covers method overriding, calling parent constructors, and when composition is a better fit than deep inheritance trees.

Prerequisites

extends Base Class

javascript
// Animal base, Dog child
class Animal {
  constructor(name) {
    this.name = name;
  }
 
  speak() {
    return `${this.name} makes a sound`;
  }
}
 
class Dog extends Animal {
  speak() {
    return `${this.name} says woof`;
  }
}
 
const rex = new Dog("Rex");
console.log(rex.speak());

super in Constructor

Child must call super() before using this:

javascript
// Pass args to parent constructor
class Employee extends Person {
  constructor(name, department) {
    super(name);
    this.department = department;
  }
}
 
class Person {
  constructor(name) {
    this.name = name;
  }
}
 
const emp = new Employee("Ada", "Engineering");
console.log(emp.name, emp.department);

Warning

Forgetting super() in a subclass constructor throws ReferenceError when you touch this.

super to Call Parent Methods

javascript
// Extend behavior, not replace entirely
class Admin extends User {
  constructor(name) {
    super(name, "admin");
  }
 
  describe() {
    return `${super.describe()} [elevated]`;
  }
}
 
class User {
  constructor(name, role) {
    this.name = name;
    this.role = role;
  }
 
  describe() {
    return `${this.name} (${this.role})`;
  }
}
 
console.log(new Admin("Lin").describe());

instanceof Along the Chain

javascript
const d = new Dog("Max");
console.log(d instanceof Dog);
console.log(d instanceof Animal);
console.log(d instanceof Object);

Overriding vs Overloading

JavaScript has no method overloading by signature—last definition wins. Use default parameters or different method names instead.

Prefer Composition When Possible

javascript
// Has-a instead of deep is-a chains
class Engine {
  start() {
    return "engine on";
  }
}
 
class Car {
  constructor() {
    this.engine = new Engine();
  }
 
  start() {
    return this.engine.start();
  }
}
 
console.log(new Car().start());

Many designs use small classes plus plain functions instead of five levels of extends.

Mini Example: Shape Hierarchy

javascript
class Shape {
  constructor(color) {
    this.color = color;
  }
}
 
class Circle extends Shape {
  constructor(color, radius) {
    super(color);
    this.radius = radius;
  }
 
  area() {
    return Math.PI * this.radius ** 2;
  }
}
 
const c = new Circle("red", 3);
console.log(c.color, c.area().toFixed(2));

FAQ

Can I extend built-ins like Array?

Possible but tricky—prefer composition or utility functions for extending array behavior.

Multiple inheritance?

Not directly—one extends parent; mixins or interfaces (TypeScript) address some cases.

Object.create vs extends?

extends is standard for class-based hierarchies; Object.create for one-off delegation.

What comes next?

Map and Set—built-in collections in the standard library.