JavaScript is a versatile language with multiple ways to solve problems. Two of the most popular paradigms are:
- Object-Oriented Programming (OOP)
- Functional Programming (FP)
Each approach organizes code differently and has its own strengths and trade-offs. Whether you are building a web app, game, or data pipeline, understanding both can help you write cleaner, more maintainable code.
Object-Oriented Programming (OOP)
OOP structures code around objects that combine:
- Properties (data)
- Methods (behavior)
This style is useful for modeling real-world entities and managing complex state.
1) Classes and Objects
A class is a blueprint. An object is an instance of that class.
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
drive() {
console.log(`${this.make} ${this.model} is driving`);
}
}
const myCar = new Car("Toyota", "Corolla");
myCar.drive(); // Toyota Corolla is driving2) Inheritance
Inheritance allows one class to extend another and reuse behavior.
class Animal {
speak() {
console.log("The animal makes a sound");
}
}
class Dog extends Animal {
speak() {
console.log("The dog barks");
}
}
const dog = new Dog();
dog.speak(); // The dog barksCommon OOP Pattern: Singleton
Use this pattern when you need exactly one shared instance.
class Database {
constructor() {
if (Database.instance) return Database.instance;
Database.instance = this;
}
}
const db1 = new Database();
const db2 = new Database();
console.log(db1 === db2); // trueOOP: Pros and Cons
| Pros | Cons |
|---|---|
| Models real-world concepts naturally | Can become complex with deep hierarchies |
| Encourages modularity and reuse | Can create tightly coupled code |
| Good for state-heavy applications | Often needs more boilerplate |
Functional Programming (FP)
FP treats code as a series of transformations using pure, composable functions. It emphasizes:
- Predictability
- Immutability
- Reusability
1) Pure Functions
A pure function always returns the same output for the same input and has no side effects.
function add(a, b) {
return a + b;
}2) Immutability
Instead of mutating existing data, create new versions.
const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4];
console.log(numbers); // [1, 2, 3]
console.log(newNumbers); // [1, 2, 3, 4]3) Higher-Order Functions
These are functions that take other functions as arguments or return functions.
function applyOperation(arr, operation) {
return arr.map(operation);
}
const result = applyOperation([1, 2, 3], (num) => num * 2);
console.log(result); // [2, 4, 6]Common FP Pattern: Function Composition
Build complex behavior by combining small, focused functions.
const multiplyBy2 = (x) => x * 2;
const add3 = (x) => x + 3;
const multiplyAndAdd = (x) => add3(multiplyBy2(x));
console.log(multiplyAndAdd(5)); // 13FP: Pros and Cons
| Pros | Cons |
|---|---|
| Predictable and easy to test | Can feel less intuitive for complex state |
| Fewer side effects | Composition chains can become hard to read |
| Strong reusability through small functions | Immutability may increase memory usage |
OOP vs FP at a Glance
| Aspect | OOP | FP |
|---|---|---|
| Data handling | Usually mutable | Prefer immutable |
| Structure | Objects with methods | Functions and transformations |
| Best for | UI/stateful systems, domain modeling | Data transformation, stateless logic |
Final Thoughts
OOP and FP are both valuable in modern JavaScript. OOP is excellent for modeling entities and managing state, while FP shines in predictable and testable transformation logic.
In practice, the best JavaScript codebases often combine both paradigms based on the problem at hand.