Inheritance is a feature that allows creating new classes based on existing ones.
With inheritance, a class can have access to the properties and methods of another, while adding or overriding them with its own methods.
This relationship between classes is known as a parent-child or superclass-subclass relationship.
In JavaScript, inheritance is primarily implemented through classes, which were introduced in ECMAScript 6 (ES6).
Before ES6, JavaScript used constructor functions and the prototype object to implement inheritance. With the introduction of class syntax, inheritance became simpler and clearer.
Basic Syntax of Inheritance
In JavaScript, to create a subclass that inherits from a base class, we use the keyword extends.
First, we need to define a base class, and then we would create the derived class. For example, like this:
class Animal {
constructor(name) {
this.name = name; // Shared property
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Calls the constructor of the parent class
this.breed = breed; // Additional property
}
speak() {
console.log(`${this.name} says Woof!`);
}
}
const myDog = new Dog('Rex', 'Labrador');
myDog.speak(); // "Rex says Woof!"
In this example:
Animalis the base class that has a constructor assigning a value tonombreand a method calledhablar().Perrois a subclass that inherits fromAnimal. It uses thesuper()method to call the base class constructor and assign the value tonombre.- Additionally, it overrides the
hablar()method to customize the specific behavior for dogs.
The super Keyword
The super() keyword allows us to get a reference to the base class from the derived class. For example, it is used to:
- Call the superclass constructor: When we need to initialize inherited properties from the base class.
- Access superclass methods: To make use of superclass methods within the subclass.
class Dog extends Animal {
constructor(name, breed) {
super(name); // Calls the constructor of the parent class
this.breed = breed; // Additional property
}
}
In the previous example,
super(nombre)calls the constructor ofAnimaland passes thenombreargument so that thenombreproperty is initialized.
Inherited Properties and Methods
When a subclass inherits from a superclass, it inherits its properties and methods. This means we can access the superclass’s properties and methods as if they were defined directly in the subclass.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Cat extends Animal {
// No need to redefine 'name', as it is inherited from Animal
}
const myCat = new Cat('Whiskers');
myCat.speak(); // "Whiskers makes a sound"
Here, Gato inherits the hablar() method from Animal and can use it without having to redefine it.
Overriding Methods in the Subclass
A feature of inheritance is that we can override the methods of the base class in the subclass. This allows us to customize the behavior.
This is useful when we want subclasses to have specific behaviors while preserving the foundation of the original class.
class Cat extends Animal {
speak() {
console.log(`${this.name} says Meow!`);
}
}
const myCat = new Cat('Rufus the cat');
myCat.speak(); // "Rufus the cat says Meow!"
In this case, Gato redefines the hablar() method to make a different sound than Animal.
Static Properties and Inheritance
Subclasses also inherit static properties. The base class and the derived class share static variables and methods (the derived class does not have its own versions)
class Animal {
static species = 'Animal'; // Static property
//... more things
}
class Dog extends Animal {}
console.log(Dog.species); // "Animal"
Dog.species = "Doggo";
console.log(Animal.species); // "Doggo"
Here,
- The static property
especieis inherited by the subclassPerro. - If we access
Perro.especiewe getAnimal. - When we modify
Perro.especie, we also modifyAnimal.especie. - That is, the
especieproperty is the same for both classes.
What is Polymorphism?
In other words, polymorphism allows objects of different classes to have different behaviors for the same method.
In JavaScript, polymorphism can be achieved using inheritance and method overriding. Let’s see it with an example:
let animal = new Animal('Animal');
let cat = new Cat('Cat');
let dog = new Dog('Dog');
animal.makeSound(); // Making sound...
cat.makeSound(); // Meow!
dog.makeSound(); // Woof!
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Making sound...');
}
}
class Cat extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log('Meow!');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log('Woof!');
}
}
In this example,
- We have an Animal class with a
makeSound()method. - The
Catclass and theDogclass inherit from theAnimalclass and override themakeSound()method with their own implementations. - When the
makeSound()method is called on each object, the behavior is different depending on the object’s class.
