Learn how to establish class hierarchies and inherit features using extends and super in JavaScript ES6. Understand subclass creation, method overriding, and prototype relationships.
In this section, we will explore the concepts of inheritance in JavaScript using the extends
and super
keywords. These tools allow us to create class hierarchies, enabling subclasses to inherit properties and methods from parent classes. This is a fundamental aspect of object-oriented programming (OOP) that promotes code reuse and organization.
Inheritance is a mechanism by which one class (the child or subclass) can inherit properties and methods from another class (the parent or superclass). This allows us to create a new class based on an existing class, extending its functionality without modifying the original class.
The extends
keyword in JavaScript is used to create a subclass that inherits from a parent class. Let’s start by looking at a simple example:
// Parent class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
// Subclass
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call the parent class constructor
this.breed = breed;
}
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Rex', 'German Shepherd');
dog.speak(); // Output: Rex barks.
In this example, we have a parent class Animal
with a constructor that initializes the name
property and a speak
method. The Dog
class extends Animal
, inheriting its properties and methods. The Dog
class also has its own constructor and a speak
method that overrides the parent class’s method.
The super()
function is used within a subclass constructor to call the constructor of its parent class. This is necessary to properly initialize the parent class’s properties within the subclass.
When you create a subclass, the JavaScript engine requires you to call super()
before you can use this
in the subclass constructor. This ensures that the parent class’s constructor is executed, setting up any necessary properties or logic.
Let’s expand on the previous example to see how super()
is used:
// Parent class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
// Subclass
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call the parent class constructor
this.breed = breed; // Initialize subclass-specific property
}
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Buddy', 'Golden Retriever');
console.log(dog.name); // Output: Buddy
console.log(dog.breed); // Output: Golden Retriever
In this example, super(name)
calls the Animal
class constructor, passing the name
argument to it. This initializes the name
property in the Animal
class, which Dog
inherits.
One of the powerful features of inheritance is the ability to override methods in subclasses. This allows a subclass to provide a specific implementation of a method that is already defined in its parent class.
Continuing with our Animal
and Dog
example, let’s see how method overriding works:
// Parent class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
// Subclass
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
// Override the speak method
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Max', 'Bulldog');
dog.speak(); // Output: Max barks.
In this example, the Dog
class overrides the speak
method of the Animal
class. When dog.speak()
is called, the overridden method in the Dog
class is executed, not the one in the Animal
class.
In JavaScript, classes are syntactical sugar over the existing prototype-based inheritance. When you use extends
, JavaScript sets up the prototype chain between the subclass and the superclass.
The prototype chain is a series of links between objects that JavaScript uses to resolve property and method lookups. When you access a property or method on an object, JavaScript first looks for it on the object itself. If it doesn’t find it, it looks up the prototype chain.
Here’s a diagram to help visualize the prototype chain when using extends
:
classDiagram Animal <|-- Dog class Animal { +String name +speak() } class Dog { +String breed +speak() }
In this diagram, Dog
inherits from Animal
. The Dog
class has access to the properties and methods of Animal
through the prototype chain.
Experiment with the following code to deepen your understanding of inheritance:
Cat
that extends Animal
.speak
method in Cat
to output a different message.Cat
that is not present in Animal
.// Your code here
extends
keyword in JavaScript?super()
function work in a subclass constructor?Remember, mastering inheritance in JavaScript is a step towards writing more organized and reusable code. As you continue to explore object-oriented programming, you’ll discover new ways to structure your applications efficiently. Keep experimenting, stay curious, and enjoy the journey!