OOP Principles, JavaScript Perspective

OOP Principles, JavaScript Perspective

OOP design principles explained with JS/TS examples.

The object-oriented programming paradigm has 4 core principles,

  • Encapsulation
  • Abstraction
  • Inheritance
  • Polymorphism

Encapsulation

Used for data hiding.

In the following example, the Movie class has two private properties,

  • _title
  • _logs

But these properties are hidden and only be get or set with their getter and setter method.

class Movie {
    private _title: string;
    private _logs: Array<string>;

    constructor(title = '') {
        this._title = title;
        this._logs = [];
    }

    public get title() {
        this._logs.push(`Getting title: ${this._title}`);
        return this._title;
    }

    public set title(title: string) {
        this._logs.push(`Setting title to: ${title}`);
        this._title = title;
    }

    public get logs() {
        return this._logs;
    }
}

const movie = new Movie();

movie.title = 'Aguner Porosmoni';
console.log(movie.title);

console.log(movie.logs); // ["Setting title to: Aguner Porosmoni", "Getting title: Aguner Porosmoni"]


// If we directly try to access the properties like `_title` or `_logs`, like below, throws an error
// Property '_title' is private and only accessible within the class 'Movie'.
// movie._title = 'Aguner Porosmoni';

Here title is not accessed directly, instead, we need to use getter and setter that are available outside to interact with the title property.

Abstraction

A technique to simplify programming structure. Abstraction hides not necessary details and minimizes complexity.

For example, pressing the gas pedal of a car increases the speed. For drivers not necessary to reveal how gas is consumed by the engine and internal mechanism.

class Circle {
  constructor(radius = 0) {
    this.radius = radius;
    this.pi = 3.14;
  }

  getArea() {
    return this.pi * Math.pow(this.radius, 2);
  }
}

Here we pass the radius and call getArea to get the area of a circle. Abstruction hides how the area calculation is being done.

Inheritance

Inheritance provides a way to create a new class from an existing class. This new class can access all the non-private properties of the existing class.

For example, we have a class called Shape. We can create a new class called Square from the Shape class.

Inheritance can be,

  • Single inheritance (FuelCar inherits Vehicle class)
  • Multiple inheritances (HybridCar inherits both ElectricCar and FuelCar classes)
  • Multi-level inheritance (GasolineCar inherits FuelCar and FuelCar inherits Vehicle class)
  • Hierarchical inheritance (Both FuelCar and ElectricCar inherits )
  • Hybrid inheritance

Polymorphism

Polymorphism allows calling methods with different signatures.

It can be

  • Method Overriding
  • Method Overloading

In the following example, we override a method called multiply. Both parent class and child class has the same method but different parameter. When we pass 3 parameters, it is handled by the childClass object. For two parameters, the object of ParentClass is invoked.

class ParentClass {
  multiply(a, b) {
    console.log(a * b);
  }
}

class ChildClass extends ParentClass {
  multiply(a, b, c) {
    // super.multiply(a, b);
    console.log(a * b * c);
  }
}

const parent = new ParentClass();
const child = new ChildClass();

parent.multiply(2, 3); // 6
child.multiply(2, 3, 4); // 24

For method overloading, we can consider the following example. We have getArea method and can take a single or double parameter. If we get both height and width, we return height * width. Otherwise, for only height, return height * height.

class Shape {
  getArea(height, width = -1) {
    if (width === -1) {
      return height * height;
    }
    return height * width;
  }
}

const shape = new Shape();
shape.getArea(5); // 25
shape.getArea(5, 6); // 30

Abstraction vs Encapsulation

  • Abstraction is design level, Encapsulation is application level
  • Abstraction hides not necessary data, and Encapsulation restricts access to prevent misuse
  • Abstraction uses an interface and abstract class to hide data, and Encapsulation uses a getter and setter to prevent direct access

Resources