DEV Community

Cover image for Dominate Object-Oriented Programming (OOP) in JavaScript.
Shafayet Hossain
Shafayet Hossain

Posted on

Dominate Object-Oriented Programming (OOP) in JavaScript.

Introduction

Object-Oriented Programming (OOP) is foundational for building well-structured, modular, and reusable code. While JavaScript was initially procedural, ES6 and beyond introduced syntax for OOP, making it an ideal language for mastering both functional and object-oriented paradigms. This article covers the fundamental OOP concepts in JavaScript, including classes, inheritance, polymorphism, and abstraction, along with JavaScript-specific features like prototype inheritance and object composition.

Key Concepts of OOP in JavaScript

1.Encapsulation:
Encapsulation allows grouping data and methods within objects, restricting direct access to an object’s state. This keeps data protected from unintended modifications and allows controlled interaction.

class Car {
    constructor(make, model) {
        this.make = make;
        this.model = model;
        this._engineOn = false;
    }

    startEngine() {
        this._engineOn = true;
        console.log(`${this.make} ${this.model} engine started.`);
    }

    stopEngine() {
        this._engineOn = false;
        console.log(`${this.make} ${this.model} engine stopped.`);
    }
}

const myCar = new Car("Toyota", "Corolla");
myCar.startEngine(); // Output: Toyota Corolla engine started.
Enter fullscreen mode Exit fullscreen mode

2.Inheritance:
Inheritance enables creating child classes based on a parent class, allowing code reuse and defining hierarchies.

class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} makes a sound.`);
    }
}

class Dog extends Animal {
    speak() {
        console.log(`${this.name} barks.`);
    }
}

const myDog = new Dog("Max");
myDog.speak(); // Output: Max barks.
Enter fullscreen mode Exit fullscreen mode

3.Polymorphism:
Polymorphism lets different classes respond to the same function or method call. JavaScript achieves polymorphism via method overriding.

class Printer {
    print() {
        console.log("Printing document...");
    }
}

class PDFPrinter extends Printer {
    print() {
        console.log("Printing PDF document...");
    }
}

const printer = new Printer();
const pdfPrinter = new PDFPrinter();

printer.print(); // Printing document...
pdfPrinter.print(); // Printing PDF document...
Enter fullscreen mode Exit fullscreen mode

4.Abstraction:
Abstraction simplifies complex systems by exposing only necessary parts. ES2020 introduced private fields with #, allowing encapsulation in classes.

class Account {
    #balance;
    constructor(initialBalance) {
        this.#balance = initialBalance;
    }
    deposit(amount) {
        this.#balance += amount;
    }
    getBalance() {
        return this.#balance;
    }
}

const myAccount = new Account(1000);
myAccount.deposit(500);
console.log(myAccount.getBalance()); // Output: 1500
Enter fullscreen mode Exit fullscreen mode

Prototype-Based Inheritance in JavaScript

JavaScript is prototype-based, meaning that objects can directly inherit from other objects rather than classes. This is achieved through prototypes, which are objects from which other objects inherit methods and properties.

function Vehicle(type) {
   this.type = type;
}

Vehicle.prototype.start = function() {
   console.log(`${this.type} is starting.`);
};

const car = new Vehicle("Car");
car.start(); // Car is starting.
Enter fullscreen mode Exit fullscreen mode

Composition over Inheritance

Composition is an alternative to inheritance where instead of creating classes in a hierarchy, you create objects that contain smaller, reusable objects to achieve desired functionality.

const canFly = {
   fly() {
       console.log("Flying!");
   }
};

const canSwim = {
   swim() {
       console.log("Swimming!");
   }
};

function Fish(name) {
   this.name = name;
}

Object.assign(Fish.prototype, canSwim);

const fish = new Fish("Nemo");
fish.swim(); // Swimming!
Enter fullscreen mode Exit fullscreen mode

Advanced OOP Patterns in JavaScript

1. Factory Pattern:
The Factory Pattern is a design pattern where you create objects without specifying the exact class. It’s useful for encapsulating the creation logic of objects.

function createUser(name, role) {
    return {
        name,
        role,
        describe() {
            console.log(`${this.name} is a ${this.role}`);
        }
    };
}

const admin = createUser("Alice", "Administrator");
admin.describe(); // Alice is an Administrator
Enter fullscreen mode Exit fullscreen mode

2. Singleton Pattern:
Singleton is a design pattern where a class has only one instance. It’s useful for creating globally accessible objects like configurations or application states.

const Singleton = (function () {
    let instance;
    function createInstance() {
        return new Object("I am the instance");
    }
    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // true
Enter fullscreen mode Exit fullscreen mode

3. Observer Pattern:
The Observer Pattern defines a dependency relationship where changes in one object (subject) lead to notifications for other objects (observers).

class Subject {
    constructor() {
        this.observers = [];
    }
    subscribe(observer) {
        this.observers.push(observer);
    }
    notify(data) {
        this.observers.forEach(observer => observer.update(data));
    }
}

class Observer {
    update(data) {
        console.log("Received update:", data);
    }
}

const subject = new Subject();
const observer1 = new Observer();
subject.subscribe(observer1);

subject.notify("New Data Available"); // Received update: New Data Available
Enter fullscreen mode Exit fullscreen mode

Challenges and Best Practices

1. Avoiding Inheritance Overuse: Favor composition for better flexibility and reuse.
2. Minimizing Side Effects: Keep data encapsulated to prevent unintended changes.
3. Using Object.freeze: This prevents accidental modifications in immutable objects.

At The End

JavaScript’s approach to OOP provides a flexible, hybrid model combining prototype-based inheritance and classical OOP. With ES6+ advancements like classes and private fields, JavaScript allows developers to build complex applications while maintaining a clean code structure. By mastering OOP in JavaScript, you can build scalable, maintainable, and performant code for real-world applications.


My personal website: https://shafayet.zya.me


A meme for you😉😉😉

Image description

Top comments (0)