JavaScript course menu
JavaScript Class Inheritance: extends, super and Method Overriding
Learn inheritance in JavaScript classes: extending a class with extends, calling the parent constructor with super(), overriding methods and calling super.method(), instanceof with subclasses, extending built-in classes like Error, and composition as an alternative.
On this page
Inheritance lets one class build on another. The new class (the subclass or child) gets everything from the existing class (the superclass or parent) and can add or change behaviour.
extends#
class Account {
constructor(owner, balance = 0) {
this.owner = owner;
this.balance = balance;
}
deposit(amount) {
this.balance += amount;
return this.balance;
}
describe() {
return `${this.owner}: ₹${this.balance}`;
}
}
class SavingsAccount extends Account {
constructor(owner, balance, interestRate) {
super(owner, balance); // run the parent constructor first
this.interestRate = interestRate;
}
addInterest() {
return this.deposit(this.balance * this.interestRate);
}
}
const savings = new SavingsAccount("Asha", 10000, 0.04);
savings.deposit(2000); // inherited
savings.addInterest(); // its own method
console.log(savings.describe()); // inheritedAsha: ₹12480class SavingsAccount extends AccountmakesSavingsAccounta subclass.- In a subclass constructor, you must call
super(...)before usingthis. It runs the parent's constructor. - The subclass can use every method of the parent.
Overriding methods#
A subclass can replace a parent method by defining one with the same name. super.methodName() calls the parent's version:
class Account {
constructor(owner, balance) {
this.owner = owner;
this.balance = balance;
}
describe() {
return `${this.owner}: ₹${this.balance}`;
}
}
class BusinessAccount extends Account {
constructor(owner, balance, company) {
super(owner, balance);
this.company = company;
}
describe() {
return `${super.describe()} (business account for ${this.company})`;
}
}
const accounts = [new Account("Ravi", 500), new BusinessAccount("Meera", 90000, "Meera Designs")];
for (const account of accounts) {
console.log(account.describe());
}Ravi: ₹500
Meera: ₹90000 (business account for Meera Designs)The loop calls describe() on each account without knowing its exact type, and each object uses its own version. This is polymorphism.
instanceof#
An instance of a subclass is also an instance of its parent:
class Animal {}
class Dog extends Animal {}
const pet = new Dog();
console.log(pet instanceof Dog);
console.log(pet instanceof Animal);
console.log(pet instanceof Array);
console.log(Object.getPrototypeOf(Dog) === Animal);true
true
false
trueExtending built-in classes#
You can extend built-in classes. The most common case is custom errors:
class HttpError extends Error {
constructor(status, message) {
super(message);
this.name = "HttpError";
this.status = status;
}
get isClientError() {
return this.status >= 400 && this.status < 500;
}
}
const error = new HttpError(404, "Page not found");
console.log(error instanceof Error, error.name, error.status, error.isClientError);true HttpError 404 trueComposition over inheritance#
Inheritance creates a tight link between classes: changes to a parent affect every child, and deep hierarchies (Animal → Mammal → Dog → ServiceDog...) become hard to change. Often it is simpler to combine smaller objects or functions instead (composition):
const canSwim = (obj) => ({ ...obj, swim: () => `${obj.name} swims` });
const canFly = (obj) => ({ ...obj, fly: () => `${obj.name} flies` });
const duck = canFly(canSwim({ name: "Duck" }));
console.log(duck.swim());
console.log(duck.fly());Duck swims
Duck fliesA useful rule: use inheritance for a clear "is a" relationship with one or two levels (a SavingsAccount is an Account), and composition for "has a" or "can do" relationships.
Practice#
Practice exercise
Create a Shape class with a name and a method describe() that returns "<name> with area <area>" using an area() method. Create Circle (radius) and Rectangle (width, height) subclasses that override area(). Print the description of a circle of radius 2 (rounded area) and a 3 by 4 rectangle.
Show solution
class Shape {
constructor(name) {
this.name = name;
}
area() {
return 0;
}
describe() {
return `${this.name} with area ${Math.round(this.area())}`;
}
}
class Circle extends Shape {
constructor(radius) {
super("Circle");
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
constructor(width, height) {
super("Rectangle");
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
for (const shape of [new Circle(2), new Rectangle(3, 4)]) {
console.log(shape.describe());
}Circle with area 13
Rectangle with area 12Key takeaway#
Finished this lesson?