The Limits of Deep Inheritance
Part of the Object Oriented Programming section of Coddy's JavaScript journey — lesson 48 of 56.
While inheritance is useful, creating very deep inheritance hierarchies (parent → child → grandchild → great-grandchild) can lead to problems. The deeper the chain, the harder it becomes to understand, maintain, and modify the code.
Let's see what happens with a deep inheritance chain:
// Base class
class Vehicle {
constructor(type) {
this.type = type;
this.isRunning = false;
}
start() {
this.isRunning = true;
console.log(`${this.type} started`);
}
}
// First level of inheritance
class Car extends Vehicle {
constructor(make, model) {
super("Car");
this.make = make;
this.model = model;
this.wheels = 4;
}
honk() {
console.log("Beep beep!");
}
}
// Second level of inheritance
class SportsCar extends Car {
constructor(make, model, topSpeed) {
super(make, model);
this.topSpeed = topSpeed;
}
race() {
this.start();
console.log(`Racing at ${this.topSpeed} mph!`);
}
}In this example, SportsCar is two levels deep in inheritance. This can lead to several problems:
- Changes to Vehicle might unexpectedly break SportsCar
- As the inheritance chain grows, it becomes harder to track where methods and properties come from
- You're forced into "is-a" relationships that might not be flexible enough
Challenge
Complete the Robot.js file to make the robot functional. Right now, the robot is built but can't do anything.
What to do in <strong>Robot.js</strong>:
- Create the speaker and the mover components inside the Robot constructor
- Use the components in the methods:
- In
greet(): Callthis.speaker.speak("Hello!"); - In
walkForward(): Callthis.mover.move("forward");
- In
Why we do this: This is composition - the robot is built by combining smaller components. The robot has-a speaker (for talking) and has-a mover (for moving), rather than inheriting these abilities.
Cheat sheet
Deep inheritance hierarchies (parent → child → grandchild) can lead to maintenance problems and inflexibility. The deeper the chain, the harder it becomes to understand and modify the code.
Example of a deep inheritance chain:
class Vehicle {
constructor(type) {
this.type = type;
this.isRunning = false;
}
start() {
this.isRunning = true;
console.log(`${this.type} started`);
}
}
class Car extends Vehicle {
constructor(make, model) {
super("Car");
this.make = make;
this.model = model;
}
}
class SportsCar extends Car {
constructor(make, model, topSpeed) {
super(make, model);
this.topSpeed = topSpeed;
}
}Problems with deep inheritance:
- Changes to base classes can unexpectedly break child classes
- Difficult to track where methods and properties originate
- Forces rigid "is-a" relationships that lack flexibility
Composition as an alternative: Instead of inheritance, use composition where objects have-a relationship with components, combining smaller parts to build functionality.
Try it yourself
import { Robot } from './Robot.js';
const myRobot = new Robot('Robo');
myRobot.greet(); // Should output: Saying: "Hello!"
myRobot.walkForward(); // Should output: Moving forwardThis lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Objects & The this Keyword
Quick Review: ObjectsAdding Methods to ObjectsUnderstanding the this KeywordConstructor FunctionsThe new KeywordRecap Challenge7 Inheritance & The extends Key
InheritanceThe "is-a" RelationshipThe extends KeywordThe super() MethodInheriting Properties&MethodsRecap Challenge2Organizing Code
What are Modules?Exporting with exportImporting with importDefault vs. Named Exports8Organizing OOP Code
Organize Classes into Modules11Project: A Shape Renderer
Setup: Shape Class & ExportCircle Class Inheritance9Static Methods & Properties
Class-Level vs. Instance-LevelStatic PropertiesStatic Utility MethodsRecap challenge