DEV Community

Cover image for The Four Pillars of OOP in JavaScript
Homayoun
Homayoun

Posted on • Updated on

The Four Pillars of OOP in JavaScript

The Four Pillars of OOP in JavaScript

Object-Oriented Programming (OOP) in JavaScript is built on four main ideas, or "pillars." These are Encapsulation, Abstraction, Inheritance, and Polymorphism. Let's break down each one with simple examples.

Encapsulation

Encapsulation means putting together data and the functions that work on that data in one place, like a class.

Example: Car

Imagine a car. It has properties like model, color, speed, and engine. It also has functions like start and stop. We put all these variables and methods into one class called Car.

class Car {
    constructor(model, color, speed, engine) {
        this.model = model;
        this.color = color;
        this.speed = speed;
        this.engine = engine;
    }

    start() {
        console.log("Car started");
    }

    stop() {
        console.log("Car stopped");
    }
}
Enter fullscreen mode Exit fullscreen mode

Abstraction

Abstraction means hiding the complex details and showing only the necessary parts.

Sure! Here's a more practical example of abstraction in JavaScript, demonstrating how you might use it in a real-world scenario such as a banking system.

Example: Banking System

In a banking system, you might have a complex set of operations for withdrawing money from an account. However, users should only need to interact with a simple interface to perform this action.

Detailed Operations (Complex Part)

Internally, the system might need to:

  • Check the account balance.
  • Verify user identity.
  • Apply transaction fees.
  • Update the account balance.
  • Log the transaction.

Simplified Interface (Abstracted Part)

For the user, the interface can be simplified to just a withdraw method. This method hides the complex operations and provides a simple way to withdraw money.

class BankAccount {
    constructor(accountNumber, balance) {
        this.accountNumber = accountNumber;
        this.balance = balance;
    }

    // Complex internal methods
    checkBalance(amount) {
        return this.balance >= amount;
    }

    verifyIdentity(userId) {
        // Dummy verification
        return true;
    }

    applyFees(amount) {
        const fee = 1; // Flat fee for simplicity
        return amount + fee;
    }

    updateBalance(amount) {
        this.balance -= amount;
    }

    logTransaction(amount) {
        console.log(`Transaction: Withdraw ${amount} from account ${this.accountNumber}`);
    }

    // Abstracted method
    withdraw(amount, userId) {
        if (this.verifyIdentity(userId) && this.checkBalance(this.applyFees(amount))) {
            this.updateBalance(this.applyFees(amount));
            this.logTransaction(amount);
            console.log(`Withdrawal successful: ${amount}`);
        } else {
            console.log(`Withdrawal failed: Insufficient funds or identity verification failed.`);
        }
    }
}

let myAccount = new BankAccount(123456, 1000);
myAccount.withdraw(100, 'user123'); // User doesn't need to know the internal workings
Enter fullscreen mode Exit fullscreen mode

In this example, the withdraw method provides a simplified interface for the user. Internally, it handles all the necessary checks and operations, but the user only needs to call one method without worrying about the details. This is the essence of abstraction in object-oriented programming.

Inheritance

Inheritance means a class can inherit properties and methods from another class.

Example: Family Traits

Just like you might inherit certain behaviors or traits from your parents, a class can inherit attributes and methods from another class. When we inherit from multiple classes, it is called multiple inheritance, but JavaScript doesn't support this directly.

class Animal {
    makeSound() {
        console.log("Animal sound");
    }
}

class Dog extends Animal {
    bark() {
        console.log("Dog barks");
    }
}

let dog = new Dog();
dog.makeSound(); // Inherited from Animal class
dog.bark();      // Specific to Dog class
Enter fullscreen mode Exit fullscreen mode

Polymorphism

Polymorphism means a variable, function, or object can take on multiple forms.

Example: Animal Class

Imagine an Animal class. With polymorphism, we can create a Cat class that modifies or adds new features to it.

class Animal {
    makeSound() {
        console.log("Animal sound");
    }
}

class Cat extends Animal {
    makeSound() { // Overriding method
        console.log("Meow");
    }
}

let cat = new Cat();
cat.makeSound(); // Calls the Cat's makeSound method
Enter fullscreen mode Exit fullscreen mode

In summary, these four pillars of OOP—Encapsulation, Abstraction, Inheritance, and Polymorphism—help make JavaScript code organized, reusable, and easier to understand.

Top comments (6)

Collapse
 
efpage profile image
Eckehard

Though I know and love the benefits of OOP in languages like Object Pascal or C++, I´m not sure we get the same benefits of OOP in Javascript:

  • Class objects can be mutated from outside making encapsulation partly useless and the code more fragile.
  • Inheritance and polymorphism without type information is kind of strange. Usually you deal with a class interface only and do not care for implementation details. This is much harder if you do not know anything about the properties you are dealing with.
  • The overwhelming use of "this" in class methods forces to write different code inside classes than outside. This is unconvenient, makes debugging harder and brings a lot of trouble if you are refractoring your code.
  • Javascript misses any form of fine grained scoping in classes. Declaring properties as private, public or published is important when classes are growing.

I really tried to write clean Javascript OOP code, but I found it less useful than I was used to in the other languages.

Collapse
 
homayunmmdy profile image
Homayoun

JavaScript's OOP features are indeed less strict compared to languages like Object Pascal or C++. Encapsulation can be compromised due to the mutable nature of objects, and lack of strong typing can make inheritance and polymorphism less intuitive. The extensive use of "this" in methods can complicate code readability and debugging, and JavaScript lacks fine-grained scoping such as private and public properties. These factors can make writing clean OOP code in JavaScript more challenging.

Collapse
 
rajatoberoi profile image
Rajat Oberoi

Good article!
I also tried to explain these concepts in my article. Let me know for any feedbacks.

dev.to/rajatoberoi/mastering-oop-e...

Collapse
 
the_riz profile image
Rich Winter

You have touched class construction in JS, but completely skipped out on the more native .prototype system.

Collapse
 
vilan profile image
coco

can you actual example for Abstraction?

Collapse
 
homayunmmdy profile image
Homayoun

Hi Bro I updated the Abstraction example with the Banking System I hope this one can help you to understand the concept better