JavaScript Inheritance
Inheritance is a way for one class to share its properties and methods with another class. This helps you reuse code and create relationships between things, like a child inheriting traits from a parent. In JavaScript, inheritance makes it easier to organize and extend your programs.
What is Inheritance?
Inheritance allows a class (called child or subclass) to acquire properties and methods from another class (called parent or superclass). This means the child class can reuse code from the parent class and add its own features.
- Parent class β The class whose properties and methods are inherited.
- Child class β The class that inherits from the parent and can add or override features.
- extends β Keyword used to create a subclass that inherits from a parent class.
- super() β Function used inside the subclass constructor to call the parent class constructor.
Parent Class
A parent class is a main class that holds properties and methods which can be shared with other classes. Think of it as a general blueprint that other classes can use to inherit features.
Hereβs an example of a parent class called Animal:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
In this example:
- Animal is the parent class.
- The constructor sets the name for each animal.
- The speak() method logs a general message about the animalβs sound.
Child Class
A child class is a class that inherits properties and methods from a parent class. This means it can use everything from the parent, and also add its own new features.
In JavaScript, we use the extends keyword to create a child class, and the super() function to call the parentβs constructor.
Hereβs an example where Dog is a child class of Animal, which adds a new method without changing any parent methods:
// Parent class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
// Child class that inherits from Animal
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call the parent constructor
this.breed = breed;
}
fetch() {
console.log(`${this.name} is fetching the ball.`);
}
}
const myDog = new Dog("Buddy", "Golden Retriever");
myDog.speak(); // Output: Buddy makes a sound.
myDog.fetch(); // Output: Buddy is fetching the ball.
// Parent class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
// Child class that inherits from Animal
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call the parent constructor
this.breed = breed;
}
fetch() {
console.log(`${this.name} is fetching the ball.`);
}
}
const myDog = new Dog("Buddy", "Golden Retriever");
myDog.speak(); // Output: Buddy makes a sound.
myDog.fetch(); // Output: Buddy is fetching the ball.
How It Works:
- Dog is a child class of Animal.
- extends lets Dog use features from Animal.
- super(name) calls the Animal constructor to set the name.
- fetch() is a new method unique to Dog that the parent class does not have.
π§ This shows how a child class can reuse the parentβs properties and methods while adding its own new behavior.
Method Overriding (Polymorphism)
Method overriding happens when a child class defines a method with the same name as one in the parent class. This lets the child class provide a specific version of the method, while still keeping the original in the parent class.
Here's an example using the same Animal parent class and a Cat child class that overrides the speak() method:
class Animal {
speak() {
console.log("The animal makes a sound.");
}
}
class Cat extends Animal {
speak() {
console.log("The cat meows.");
}
}
const animal = new Animal();
animal.speak(); // Output: The animal makes a sound.
const kitty = new Cat();
kitty.speak(); // Output: The cat meows.
class Animal {
speak() {
console.log("The animal makes a sound.");
}
}
class Cat extends Animal {
speak() {
console.log("The cat meows.");
}
}
const animal = new Animal();
animal.speak(); // Output: The animal makes a sound.
const kitty = new Cat();
kitty.speak(); // Output: The cat meows.
How It Works:
- The Animal class has a speak() method that logs a general message.
- The Cat class overrides speak() with its own message.
- When speak() is called on a Cat object, the overridden version runs instead of the parent one.
π§ Method overriding lets you change or improve inherited behavior without modifying the parent class, making your code more flexible and reusable.
Prototype-Based Inheritance (Before ES6)
Before JavaScript introduced class syntax in ES6, inheritance was done using functions and prototypes. This is called prototype-based inheritance. While it still works today, it's considered the older way of doing things and is less commonly used in modern JavaScript.
Hereβs how it works using constructor functions and the prototype property:
// Parent constructor function
function Animal(name) {
this.name = name;
}
// Adding method to Animal prototype
Animal.prototype.speak = function () {
console.log(this.name + " makes a sound.");
};
// Child constructor function
function Dog(name) {
Animal.call(this, name); // Call the parent constructor
}
// Inherit from Animal prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// Overriding the speak method in Dog
Dog.prototype.speak = function () {
console.log(this.name + " barks.");
};
// Create a new Dog object
const myDog = new Dog("Rocky");
myDog.speak(); // Output: Rocky barks.
// Parent constructor function
function Animal(name) {
this.name = name;
}
// Adding method to Animal prototype
Animal.prototype.speak = function () {
console.log(this.name + " makes a sound.");
};
// Child constructor function
function Dog(name) {
Animal.call(this, name); // Call the parent constructor
}
// Inherit from Animal prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// Overriding the speak method in Dog
Dog.prototype.speak = function () {
console.log(this.name + " barks.");
};
// Create a new Dog object
const myDog = new Dog("Rocky");
myDog.speak(); // Output: Rocky barks.
How It Works:
- Animal and Dog are constructor functions (used before ES6 classes).
- Animal.prototype.speak defines a method shared by all Animal instances.
- Dog.prototype = Object.create(Animal.prototype) sets up inheritance so Dog can use Animal's methods.
- Dog.prototype.speak overrides the inherited method with a custom one.
π§ While prototype-based inheritance is more complex and harder to read, it was the standard way to implement inheritance in JavaScript before classes were introduced in ES6.
Real-World Example: Vehicles
Letβs look at a real-world example using vehicles to understand how inheritance works in JavaScript. We'll start with a parent class called Vehicle and then create child classes like Car and Bike that inherit from it.
// π¨βπ§βπ¦ Parent class - This is the base class all vehicles will inherit from
class Vehicle {
// ποΈ Parent constructor - sets the brand for any vehicle
constructor(brand) {
this.brand = brand;
}
// π Method to start engine
startEngine() {
console.log(`${this.brand} engine started.`);
}
}
// π Child class 1 - Car inherits from Vehicle
class Car extends Vehicle {
// π§± Child constructor - adds a new property 'doors' in addition to brand
constructor(brand, doors) {
super(brand); // π Calls parent constructor to set the brand
this.doors = doors;
}
// π Method overriding - provides a custom version of startEngine()
startEngine() {
console.log(`${this.brand} car with ${this.doors} doors is ready to drive.`);
}
}
// ποΈ Child class 2 - Bike inherits from Vehicle
class Bike extends Vehicle {
// π§± Child constructor - adds a new property 'type' in addition to brand
constructor(brand, type) {
super(brand); // π Calls parent constructor to set the brand
this.type = type;
}
// π Method overriding - custom behavior for starting a bike engine
startEngine() {
console.log(`${this.brand} ${this.type} bike engine roars!`);
}
}
// β
Creating instances and using the classes
const myCar = new Car("Toyota", 4);
myCar.startEngine();
const myBike = new Bike("Yamaha", "sport");
myBike.startEngine();
// π¨βπ§βπ¦ Parent class - This is the base class all vehicles will inherit from
class Vehicle {
// ποΈ Parent constructor - sets the brand for any vehicle
constructor(brand) {
this.brand = brand;
}
// π Method to start engine
startEngine() {
console.log(`${this.brand} engine started.`);
}
}
// π Child class 1 - Car inherits from Vehicle
class Car extends Vehicle {
// π§± Child constructor - adds a new property 'doors' in addition to brand
constructor(brand, doors) {
super(brand); // π Calls parent constructor to set the brand
this.doors = doors;
}
// π Method overriding - provides a custom version of startEngine()
startEngine() {
console.log(`${this.brand} car with ${this.doors} doors is ready to drive.`);
}
}
// ποΈ Child class 2 - Bike inherits from Vehicle
class Bike extends Vehicle {
// π§± Child constructor - adds a new property 'type' in addition to brand
constructor(brand, type) {
super(brand); // π Calls parent constructor to set the brand
this.type = type;
}
// π Method overriding - custom behavior for starting a bike engine
startEngine() {
console.log(`${this.brand} ${this.type} bike engine roars!`);
}
}
// β
Creating instances and using the classes
const myCar = new Car("Toyota", 4);
myCar.startEngine();
const myBike = new Bike("Yamaha", "sport");
myBike.startEngine();
How It Works:
- Vehicle is the parent class that defines shared behavior for all vehicles.
- Car and Bike are child classes that use extends to inherit from Vehicle.
- super() is used inside the child class constructors to call the parentβs constructor and initialize shared properties like brand.
- Both child classes override the startEngine() method to provide specific behavior.
- This is a real example of inheritance: the child classes reuse and customize behavior from the parent class.
Output
Toyota car with 4 doors is ready to drive.
Yamaha sport bike engine roars!
Toyota car with 4 doors is ready to drive.
Yamaha sport bike engine roars!
π§ Inheritance helps avoid code duplication and makes it easy to organize related types of objects with shared behavior.
Frequently Asked Questions
What is inheritance in JavaScript?
What is inheritance in JavaScript?
Inheritance in JavaScript allows one class (child) to acquire properties and methods from another class (parent), enabling code reuse and organization.
What does the extends keyword do in JavaScript?
What does the extends keyword do in JavaScript?
The extends keyword is used to create a child class that inherits from a parent class, allowing the child class to access and reuse parent methods and properties.
What is the purpose of the super() function in JavaScript?
What is the purpose of the super() function in JavaScript?
The super() function is used inside a child class constructor to call the constructor of the parent class. It helps initialize the inherited properties.
Can a child class override methods from a parent class?
Can a child class override methods from a parent class?
Yes, a child class can override methods from a parent class by defining a method with the same name. This is known as method overriding or polymorphism.
How was inheritance handled before classes were introduced in ES6?
How was inheritance handled before classes were introduced in ES6?
Before ES6, inheritance in JavaScript was implemented using constructor functions and the prototype chain. This is known as prototype-based inheritance.
π What's Next?
Up next, you'll learn about encapsulation in JavaScript. Encapsulation is a way to keep parts of your code private and protected, so that only the necessary parts can be accessed or changed. This helps make your code safer, easier to manage, and less likely to break by mistake.