Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

JavaScript Inheritance Patterns

A classic interview topic, but understanding it thoroughly also has real practical value. JS has many inheritance patterns, each suited to different situations.

Prototype Chain Inheritance

javascript
function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function () {
  return `${this.name} makes a sound`;
};

function Dog(name) {
  this.name = name;
}
Dog.prototype = new Animal(); // prototype chain inheritance

const dog = new Dog("Rex");
dog.speak(); // 'Rex makes a sound'

Problem: all subclass instances share reference-type properties on the prototype.

javascript
function Animal() {
  this.friends = []; // reference type
}
Dog.prototype = new Animal();

const d1 = new Dog();
const d2 = new Dog();
d1.friends.push("cat");
console.log(d2.friends); // ['cat'] ← d2 is also affected!

Constructor Inheritance (Borrowing Constructors)

javascript
function Animal(name) {
  this.name = name;
  this.friends = [];
}

function Dog(name, breed) {
  Animal.call(this, name); // call the parent constructor inside the child
  this.breed = breed;
}

const d1 = new Dog("Rex", "Shiba");
const d2 = new Dog("Noir", "Labrador");
d1.friends.push("cat");
console.log(d2.friends); // [] ← no cross-contamination

Problem: cannot inherit methods from the parent prototype (Animal.prototype.speak is not available).

Combination Inheritance (Most Common Classic Pattern)

javascript
function Animal(name) {
  this.name = name;
  this.friends = [];
}
Animal.prototype.speak = function () {
  return `${this.name} makes a sound`;
};

function Dog(name, breed) {
  Animal.call(this, name); // 1. inherit properties
  this.breed = breed;
}
Dog.prototype = new Animal(); // 2. inherit methods
Dog.prototype.constructor = Dog; // 3. fix constructor

const dog = new Dog("Rex", "Shiba");
dog.speak(); // ✅ can call parent method
dog.friends; // ✅ independent, not shared

Problem: Animal is called twice (performance waste).

Object.create: Parasitic Combination Inheritance (Best Classic Pattern)

javascript
function Animal(name) {
  this.name = name;
  this.friends = [];
}
Animal.prototype.speak = function () {
  return `${this.name} makes a sound`;
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

// Key: use Object.create instead of new Animal() — avoids calling parent constructor twice
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// Subclass methods
Dog.prototype.bark = function () {
  return "Woof!";
};

ES6 class (Modern Approach)

javascript
class Animal {
  constructor(name) {
    this.name = name;
    this.friends = [];
  }

  speak() {
    return `${this.name} makes a sound`;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // must call super first
    this.breed = breed;
  }

  bark() {
    return "Woof!";
  }
}

const dog = new Dog("Rex", "Shiba");
dog.speak(); // 'Rex makes a sound'
dog.bark(); // 'Woof!'
dog instanceof Animal; // true
dog instanceof Dog; // true

Summary

PatternInherits PropertiesInherits MethodsRecommended
Prototype chain❌ shared
Constructor
CombinationUsable but has perf issue
Parasitic combination✅ Best pre-ES6
ES6 class✅ Modern first choice

Use ES6 class for new code. Understanding prototype chain inheritance is for reading legacy code and acing interviews.

MIT Licensed