JavaScript Class Inheritance

Published: 31 May, 2023

6 mins

Read on dev.to

9 reactions

##Prerequisite:

A good understanding of how JavaScript classes work and how to use it. Check out my blog post on Introduction to JavaScript class example and usage, if you're not familiar with how to use JavaScript classes.

Introduction

One of the most powerful features of JavaScript is its ability to support inheritance, which is one of the fundamental principle of Object-Oriented Programming (OOP).

The main concept of inheritance is the ability of a class to derive attributes and functionalities from another class, enabling the extension of class's capabilities.

Prior to ES6 Implementing a proper inheritance require multiple steps. One of the strategies used was [PROTOTYPE INHERITANCE](Inheritance and the prototype chain - JavaScript | MDN).

Class inheritance involves two part:

  • Parent Class (Super Class): A class whose attributes and functionalities are inherited from.

  • Child Class (Sub Class): A class that derives attributes and functionalities from another class.

The parent class properties and functionalities are inherited by the child class.

Why Class Inheritance?

Inheritance gives developer the ability to write less code, which saves cost and time.

Inheritance helps to extend the functionalities of a class and support code reusability.

"Any piece of useful software will sooner or later change, not necessarily because it is erroneous, but rather because it is desirable to enhance its functionalities" - Mezini, Mira.

The extends Keyword

The extends keyword provides a class with the ability to acquire properties and methods from another class. When used to declare or define a class, it automatically turns the class into a child class. extends helps to establish a relationship between classes.

Syntax

class ClassName extends ParentClass {
    /* ... */
}

class - the keyword for defining a class

ClassName - the name child class

extends - JavaScript keyword used to extend the functionality of the parent class

ParentClass - super class whose functionality are derived from

Using the extends keyword on a class is the starting point for implementing inheritance.

// Parent Class
class Vehicle {
    constructor(name, model){
        this.name = name;
        this.model = model;
    }
    details(){
        console.log(`${this.name}, model ${this.model}`);
    }
}
 
// Child Class
class Car extends Vehicle {
    topSpeed(){
       this.speed = '168mph';
       console.log(`${this.name} ${this.model} maxes out at ${this.speed}`);
    }
}
 
const suv = new Car('Tesla', 'X Plaid'); // Creating Car Object
suv.details() // Tesla, model X Plaid
 
suv.topSpeed(); // Tesla model X Plaid maxes out at 168mph

In the example above we, created a Vehicle class with some class members in the class body. Then we created a Car class that extends the parent class. We defined a method where we create and initialize the top speed of the car, and then we log out the details.

In the example, the extends keyword shows how powerful it is to extend the functionality of the super class. When used on the child class, the extends keyword gives us the privilege to access the parent class's properties and methods, including the constructor, thereby making it become part of the child class.

Overriding

Overriding is an OOP term where a particular method in the subclass has the same name as the method in the parent class. When an instance of the subclass gets called on the method, the subclass method get implemented instead of the super class method.

Method Overriding

When we use the extends keyword on the child class, we inherit all the methods declared on the parent class by default. Method overriding allows us to replace the code of the parent class with the child class method, given that they share the same name.

However, we don't want to actually replace the method of the parent class, but to build upon it by extending its functionality, since that's what the concept of inheritance is all about.

JavaScript provides a way to extend method functionality without completely replacing the parent class method with the use of super keyword and super().

The super keyword can be used as an object or as a function look up

Overriding method using the super

The  super keyword allows us to access an overridden method of a parent class in a subclass. By using the super keyword in a subclass method, we can extend the functionalities of the parent class method. This usage of super treats it an object.

Syntax

super.methodName()
class Animal {
    makeSound(){
        console.log('Make Sound')    
    }
}
class Dog extends Animal {
    makeSound(){
        super.makeSound();
        console.log('Woof! Woof!!');
    }
}
const dog = new Dog();
dog.makeSound(); // Make Sound Woof! Woof!!

In the example above, we created an Animal class which has makeSound method. We then extend the 'Dog' class and override the makeSound method. We call the parent class method using super and then we log out the sound made by the dog.

Overriding constructor using super()

By default, every subclass will inherits the constructor of the parent class. When we define or declare a constructor in the subclass, we have successfully overridden the parent class constructor.

Overriding a constructor provides the subclass with its own code logic and attributes.

Using super in constructor is a slightly different. Here, the super is used as a function call in the subclass constructor. When overriding a constructor in the subclass, the super constructor must be called first before using this.

A ReferenceError is raised if this keyword is used before calling the super constructor super().

class Vehicle {
    constructor(brand){
    this.brand = brand;
    }
 
    displayBrand(){
        console.log(`Brand: ${this.brand}`);    
    }
 
}
class Car extends Vehicle{
    constructor(brand, model, color){
        super(brand);
        this.model = model;
        this.color = color;
    }
    displayDetails(){
       console.log(`Details: ${this.model} ${this.color}`);
    }
}
const car1 = new Car('Tesla', 'Model X', 'Cherry')
car1.displayBrand(); // Tesla
car1.displayDetails(); // Details: Model X Cherry

In the example above, the Vehicle class is defined with a constructor that accepts a brand parameter and initializes the brand property. The displayBrand method is defined which prints out the brand property.

The Car class is defined and extends the Vehicle class. The class defines its own constructor property, and the super(brand) is used to invoke the super class constructor, with a parameter of brand is passed in. The Car class also has the displayDetails method which prints out the model and color.

Later, an instance of the Car is created, arguments are passed into the constructor of the Car class, then we call displayBrand and displayDetails on the object instance.

The super keyword is used to access the properties and methods of parent class while the super() is used within the constructor of a subclass as a function call to access the public field of a parent class before accessing this.

Property accessor getters and setters

JavaScript accessor properties allow us to access (get) and modify (set) class or object properties. The accessor properties are functions that execute on setting or getting a value. They are usually denoted using the get and set keywords.

Accessor Terms

  • Setter - A setter is a function that is used to assign a value to class properties. The set keyword is used to define the setter function, and it must accept exactly one parameter or value that represents the new value to assign to the property. By defining a function as a setter, it means that you can only write to the class property by assigning a new value.

  • Getters - A getter is a function that helps us to get a class property value after it has been set. The get keyword is used to define the getter function. You can only read the property value of a getter function.

class Person {
    constructor(){
        this._name = ''; 
    }
 
    set name(value){
        return this._name = value;  
    }
 
    get name(){
        return this._name;
    }
}
 
class Student extends Person {
    constructor(){
        super();
        this._college = '';
        this._noOfCourse = '';
    }
 
    set college(value){
       return this._college = value;
    }
 
    get college(){
       return this._college;
    }
 
     set noOfCourse(value){
        return this._noOfCourse = value;
   }
 
    get noOfCourse(){
        return this._noOfCourse;
    }
}
const student = new Student();
console.log(student.name) // ''
student.name = 'John';
console.log(student.name); //John
student.college = 'Standford';
console.log(student.college); // Standford
student.noOfCourse = 12;
console.log(student.noOfCourse) //12

In the Person class, the setter and getter are defined, which help to set and get the name property. The set method has a value parameter that is used to set the name property, and the get method which only return the set name.

In the derived class Student, we call the parent constructor using super, then we declare some properties that are unique to the class. We define get and set methods of the class properties, which help us to set and retrieve basic information such as the college and the noOfCourse.

We created an instance of our class student, then we set and get the class properties using the class instance.

Note how we call our get method; there are no parentheses after the method name. A TypeError is raised if parentheses are included.

Summary

JavaScript Inheritance gives us the privilege to extend the functionality of a class. The extends keyword enables a subclass to derive properties and functions from the parent class. The super keyword allows us to call and invoke the parent class's methods and properties, while the super() is used within a subclass constructor as a function look-up to call the parent class constructor's public fields before accessing this. Accessor properties, including setters and getters can be used to modify and access class properties using the set and get functions.

Conclusion

In JavaScript, inheritance gives developer the ability to write modular and concise JavaScript codes and helps to extend the functionality of a class by building on top of the existing class.

THE END