JavaScript Class Inheritance
Tags: javascript, webdev, tutorial, programming
Published: 2023-05-31 12:50:43

##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](https://dev.to/bolajibolajoko51/introduction-to-javascript-classes-basics-syntax-and-example-usage-1734), 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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)).

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**

```javascript
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.

```javascript
// 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**

```javascript
super.methodName()
```

```javascript
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()`.

```javascript
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.
  

```javascript
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.