JavaScript Class Inheritance
Learn how classes can inherit from other classes
🧬 What is Class Inheritance?
Inheritance allows a class to inherit properties and methods from another class. The child class gets all features of the parent class and can add its own unique features.
// Parent class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
// Child class inherits from Animal
class Dog extends Animal {
speak() {
return `${this.name} barks`;
}
}
const myDog = new Dog("Buddy");
console.log(myDog.speak());
Output:
Buddy barks
Key Inheritance Concepts
extends
Keyword to create inheritance
class Child extends Parent {
// Child class code
}
super()
Calls parent class constructor
constructor(name) {
super(name);
}
Override
Replace parent class methods
speak() {
return "New behavior";
}
Extend
Add new methods to child class
newMethod() {
return "Child only method";
}
🔹 Basic Inheritance Example
Let's see how a child class inherits from a parent class:
// Parent class (Base class)
class Vehicle {
constructor(brand, year) {
this.brand = brand;
this.year = year;
}
start() {
return `${this.brand} vehicle is starting...`;
}
getInfo() {
return `${this.year} ${this.brand}`;
}
}
// Child class (Derived class)
class Car extends Vehicle {
constructor(brand, year, doors) {
super(brand, year); // Call parent constructor
this.doors = doors; // Add new property
}
// Override parent method
start() {
return `${this.brand} car engine is starting...`;
}
// Add new method
honk() {
return `${this.brand} car goes beep beep!`;
}
}
// Using inheritance
const myCar = new Car("Toyota", 2023, 4);
console.log(myCar.getInfo()); // Inherited from Vehicle
console.log(myCar.start()); // Overridden method
console.log(myCar.honk()); // New method
Output:
2023 Toyota
Toyota car engine is starting...
Toyota car goes beep beep!
🔹 Using super() Keyword
The super() keyword is used to call parent class methods:
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
work() {
return `${this.name} is working`;
}
getDetails() {
return `Employee: ${this.name}, Salary: $${this.salary}`;
}
}
class Manager extends Employee {
constructor(name, salary, department) {
super(name, salary); // Call parent constructor
this.department = department;
}
// Override with super call
work() {
const parentWork = super.work(); // Call parent method
return `${parentWork} and managing ${this.department}`;
}
// Override with additional info
getDetails() {
const parentDetails = super.getDetails(); // Call parent method
return `${parentDetails}, Department: ${this.department}`;
}
// New method
holdMeeting() {
return `${this.name} is holding a ${this.department} meeting`;
}
}
const manager = new Manager("Alice", 75000, "IT");
console.log(manager.work());
console.log(manager.getDetails());
console.log(manager.holdMeeting());
Output:
Alice is working and managing IT
Employee: Alice, Salary: $75000, Department: IT
Alice is holding a IT meeting
🔹 Multi-Level Inheritance
Classes can inherit from other classes that also inherit:
// Grandparent class
class Shape {
constructor(color) {
this.color = color;
}
describe() {
return `This is a ${this.color} shape`;
}
}
// Parent class
class Rectangle extends Shape {
constructor(color, width, height) {
super(color);
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
describe() {
return `${super.describe()} with area ${this.area()}`;
}
}
// Child class
class Square extends Rectangle {
constructor(color, side) {
super(color, side, side); // Square has equal width and height
this.side = side;
}
describe() {
return `${super.describe()} (it's a square!)`;
}
perimeter() {
return this.side * 4;
}
}
const mySquare = new Square("red", 5);
console.log(mySquare.describe());
console.log(`Perimeter: ${mySquare.perimeter()}`);
console.log(`Area: ${mySquare.area()}`);
Output:
This is a red shape with area 25 (it's a square!)
Perimeter: 20
Area: 25
🔹 Real-World Example: Game Characters
Let's create a game character system using inheritance:
// Base character class
class Character {
constructor(name, health, level) {
this.name = name;
this.health = health;
this.maxHealth = health;
this.level = level;
}
attack() {
return `${this.name} attacks for 10 damage`;
}
heal(amount) {
this.health = Math.min(this.health + amount, this.maxHealth);
return `${this.name} healed for ${amount}. Health: ${this.health}/${this.maxHealth}`;
}
getStatus() {
return `${this.name} (Level ${this.level}) - Health: ${this.health}/${this.maxHealth}`;
}
}
// Warrior class
class Warrior extends Character {
constructor(name, health, level) {
super(name, health, level);
this.armor = 5;
}
attack() {
return `${this.name} swings sword for 15 damage`;
}
defend() {
return `${this.name} raises shield, reducing damage by ${this.armor}`;
}
}
// Mage class
class Mage extends Character {
constructor(name, health, level) {
super(name, health, level);
this.mana = 50;
}
attack() {
if (this.mana >= 10) {
this.mana -= 10;
return `${this.name} casts fireball for 20 damage (Mana: ${this.mana})`;
}
return `${this.name} is out of mana!`;
}
castHeal() {
if (this.mana >= 15) {
this.mana -= 15;
this.heal(25);
return `${this.name} casts heal spell (Mana: ${this.mana})`;
}
return `${this.name} doesn't have enough mana to heal`;
}
}
// Create characters
const warrior = new Warrior("Conan", 100, 5);
const mage = new Mage("Gandalf", 80, 7);
console.log(warrior.getStatus());
console.log(warrior.attack());
console.log(warrior.defend());
console.log(mage.getStatus());
console.log(mage.attack());
console.log(mage.castHeal());
Output:
Conan (Level 5) - Health: 100/100
Conan swings sword for 15 damage
Conan raises shield, reducing damage by 5
Gandalf (Level 7) - Health: 80/80
Gandalf casts fireball for 20 damage (Mana: 40)
Gandalf casts heal spell (Mana: 25)
🔹 Method Overriding vs Method Overloading
Understanding different ways to modify inherited behavior:
class Animal {
constructor(name, species) {
this.name = name;
this.species = species;
}
makeSound() {
return `${this.name} makes a generic animal sound`;
}
move() {
return `${this.name} moves around`;
}
}
class Bird extends Animal {
constructor(name, canFly = true) {
super(name, "Bird");
this.canFly = canFly;
}
// Method Overriding - completely replace parent method
makeSound() {
return `${this.name} chirps and tweets`;
}
// Method Overriding with super - extend parent method
move() {
const baseMove = super.move();
if (this.canFly) {
return `${baseMove} and flies through the sky`;
}
return `${baseMove} by walking and hopping`;
}
// New method - only available in Bird class
buildNest() {
return `${this.name} is building a nest`;
}
}
class Penguin extends Bird {
constructor(name) {
super(name, false); // Penguins can't fly
}
// Override Bird's makeSound
makeSound() {
return `${this.name} makes penguin sounds`;
}
// New method specific to penguins
swim() {
return `${this.name} swims gracefully underwater`;
}
}
const robin = new Bird("Robin");
const penguin = new Penguin("Pingu");
console.log(robin.makeSound());
console.log(robin.move());
console.log(robin.buildNest());
console.log(penguin.makeSound());
console.log(penguin.move());
console.log(penguin.swim());
Output:
Robin chirps and tweets
Robin moves around and flies through the sky
Robin is building a nest
Pingu makes penguin sounds
Pingu moves around by walking and hopping
Pingu swims gracefully underwater