Mastering OOP: Encapsulation, Abstraction, Inheritance, and Polymorphism Explained with JavaScript Examples
Tags: javascript, programming, beginners, oop
Published: 2024-06-18 07:06:04

Four fundamental concepts of Object-Oriented Programming (OOP)

## 1. Encapsulation

- Bundling the data (properties) and methods (functions) that operate on the data into a single unit, typically a class or an object.
- It restricts direct access to some of the object's components, which can help prevent the accidental modification of data. Instead, interactions with the data are done through well-defined interfaces (methods).


< Procedural way of code >

```
let baseSalary = 30000;
let overtime = 10;
let rate = 20;

function getWage(baseSalary, overtime, rate) {
    return baseSalary + (overtime * rate)
}
```

< OOP way >

```
let employee = {
    baseSalary: 30000,
    overtime: 10,
    rate: 20,
    getWage: function() {
        return this.baseSalary + (this.overtime * this.rate);
    }
}

console.log(employee.getWage())
```

- In OOP way functions will have fewer parameters. And hence easier to manage.
- Parameters modeled as properties of this object.
- Data (baseSalary, overtime, rate) and functionality (getWage method) are encapsulated within a single object employee.

## 2. Abstraction

Abstraction in JavaScript (or any programming language) involves hiding the complex implementation details and showing only the necessary features of an object.
This helps in reducing complexity and increases the efficiency of the program by allowing the user to interact with the object at a higher level.

```
class Car {

    constructor(make, model, year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    startEngine() {
        this.#checkEngine();
        console.log(`${this.make} ${this.model} engine started.`);
    }

    drive() {
        console.log(`${this.make} ${this.model} is driving.`)
    }
    
    #checkEngine() {
        console.log('Check engine...')
    }
}

const myCar = new Car('Tata','Punch', 2024);
myCar.startEngine();
myCar.drive();
// myCar.#checkEngine(); //--> SyntaxError: Private field '#checkEngine' must be declared in an enclosing class
```

- Private method checkEngine cannot be accessed outside the class because it has a private identifier.  #checkEngine is an example of a private method (a feature introduced in ES2022).

- The startEngine method provides a simple interface for the user, while the complex logic inside #checkEngine is hidden, demonstrating abstraction.

## 3. Inheritance

- Helps us to prevent redundant code.
- Allows a class to inherit properties and methods from another class. In JavaScript, inheritance can be implemented using the class syntax with the extends keyword.

```
// Base class
class Vehicle {
    constructor(make, model, year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    drive() {
        console.log(`${this.make} ${model} driving.`)
    }
}

//The Car class inherits from the Vehicle class. This means that Car has access to the properties and methods defined in Vehicle
class Car extends Vehicle {
    constructor(make, model, year, color) {
        super(make, model, year);
        this.color = color;
    }

    getColor() {
        console.log(`Color of ${this.make} ${this.model} is ${this.color}`)
    }
}

const myCar = new Car('Tata', 'Punch', '2024', 'Grey');
myCar.getColor()
```

## 4. Polymorphism

- Poly means Many, morphism means Forms.
- In polymorphism the same method results in different actions depending on the object it is acting upon.
- In programming terms, the remote control calls the power method, and each device has its own implementation of what happens when the power method is called.
- This is polymorphism: the same method (power) results in different actions depending on the object it is acting upon (TV, DVD player, or radio).

```

// Base class
class Device {
    power() {
        throw new Error('power method must be implemented');
    }
}

// Derived class for TV
class TV extends Device {
    power() {
        console.log('Turning TV on or off.');
    }
}

// Derived class for DVD Player
class DVDPlayer extends Device {
    power() {
        console.log('Turning DVD Player on or off.');
    }
}

// Derived class for Radio
class Radio extends Device {
    power() {
        console.log('Turning Radio on or off.');
    }
}

// Function that demonstrates polymorphism
function useRemoteControl(device) {
    device.power();
}

// Usage
const myTV = new TV();
const myDVDPlayer = new DVDPlayer();
const myRadio = new Radio();

useRemoteControl(myTV);        // Output: Turning TV on or off.
useRemoteControl(myDVDPlayer); // Output: Turning DVD Player on or off.
useRemoteControl(myRadio);     // Output: Turning Radio on or off.

```