Inheritance lets a class (the subclass, child class, or derived class) acquire the properties and methods of another class (the superclass, parent class, or base class), while adding or overriding behavior of its own. It models an 'is-a' relationship: a Dog is an Animal, a Manager is an Employee.
class Animal {
protected name
function __construct(name) { this.name = name }
function eat() {
return this.name + " is eating."
}
function makeSound() {
return this.name + " makes a sound."
}
}
class Dog extends Animal {
function makeSound() {
return this.name + " barks." // overrides the parent's version
}
function fetch() {
return this.name + " fetches the ball." // adds new behavior
}
}
rex = new Dog("Rex")
rex.eat() // "Rex is eating." — inherited unchanged from Animal
rex.makeSound() // "Rex barks." — overridden in Dog
rex.fetch() // "Rex fetches the ball." — new to Dog
Why inheritance is useful: it avoids duplicating shared logic across related classes. If ten different animal types all need an eat() method with identical logic, writing it once in Animal and inheriting it is far more maintainable than copy-pasting it into every subclass.
A critical caution: inheritance creates tight coupling — a change to the parent class can silently break every subclass. Deep inheritance hierarchies (a class inheriting from a class inheriting from a class, several levels deep) are notoriously hard to understand and maintain. Modern OOP guidance (covered further in the Composition chapter) increasingly favors inheritance only for genuine 'is-a' relationships, and reaches for composition in many other cases.