
OOP vs Functional Programming
Programming paradigms are approaches to how we structure and think about code. Object-Oriented and Functional are the two most widely used paradigms.
Object-Oriented Programming (OOP)
Core Concept
OOP bundles data and methods that process that data into objects.
// Object-Oriented approach
class BankAccount {
constructor(owner, balance) {
this.owner = owner;
this.balance = balance;
}
deposit(amount) {
this.balance += amount;
return this.balance;
}
withdraw(amount) {
if (this.balance >= amount) {
this.balance -= amount;
return this.balance;
}
throw new Error("Insufficient funds");
}
}
const account = new BankAccount("John", 10000);
account.deposit(5000); // 15000
account.withdraw(3000); // 12000
Four Pillars of OOP
1. Encapsulation
class User {
#password; // private field
constructor(username, password) {
this.username = username;
this.#password = this.#hashPassword(password);
}
#hashPassword(password) {
return btoa(password);
}
verifyPassword(inputPassword) {
return this.#hashPassword(inputPassword) === this.#password;
}
}
2. Inheritance
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.`);
}
}
3. Polymorphism
class Shape {
area() {
throw new Error("Implementation required");
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
4. Abstraction
class CoffeeMachine {
#water = 0;
#beans = 0;
addWater(amount) {
this.#water += amount;
}
addBeans(amount) {
this.#beans += amount;
}
makeCoffee() {
if (this.#water < 100 || this.#beans < 10) {
throw new Error("Insufficient ingredients");
}
this.#water -= 100;
this.#beans -= 10;
return "☕ Coffee ready!";
}
}
Functional Programming (FP)
Core Concept
FP centers on pure functions and immutability.
// Functional approach
const createAccount = (owner, balance) => ({
owner,
balance
});
const deposit = (account, amount) => ({
...account,
balance: account.balance + amount
});
const withdraw = (account, amount) => {
if (account.balance >= amount) {
return {
...account,
balance: account.balance - amount
};
}
throw new Error("Insufficient funds");
};
// Usage (original data unchanged)
const account1 = createAccount("John", 10000);
const account2 = deposit(account1, 5000);
const account3 = withdraw(account2, 3000);
console.log(account1.balance); // 10000 (original preserved)
console.log(account3.balance); // 12000
Core Principles of FP
1. Pure Functions
// Pure function (Good)
const add = (a, b) => a + b;
add(2, 3); // Always 5
// Impure function (Bad)
let total = 0;
const addToTotal = (value) => {
total += value; // Modifies external state
return total;
};
2. Immutability
// Bad: Mutating original
const numbers = [1, 2, 3];
numbers.push(4); // Mutates original
// Good: Creating new array
const numbers2 = [1, 2, 3];
const newNumbers = [...numbers2, 4]; // New array
3. Higher-Order Functions
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
4. Function Composition
const compose = (...fns) => (x) =>
fns.reduceRight((acc, fn) => fn(acc), x);
const addOne = (x) => x + 1;
const double = (x) => x * 2;
const square = (x) => x ** 2;
const calculate = compose(square, double, addOne);
console.log(calculate(3)); // ((3 + 1) * 2) ** 2 = 64
Comparison: Shopping Cart Implementation
Object-Oriented Approach
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(product, quantity) {
const existingItem = this.items.find(item => item.product.id === product.id);
if (existingItem) {
existingItem.quantity += quantity;
} else {
this.items.push({ product, quantity });
}
}
getTotal() {
return this.items.reduce((sum, item) =>
sum + (item.product.price * item.quantity), 0
);
}
}
Functional Approach
const createCart = () => [];
const addItem = (cart, product, quantity) => {
const existingItem = cart.find(item => item.product.id === product.id);
if (existingItem) {
return cart.map(item =>
item.product.id === product.id
? { ...item, quantity: item.quantity + quantity }
: item
);
}
return [...cart, { product, quantity }];
};
const getTotal = (cart) =>
cart.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
Pros and Cons
OOP Advantages
- Intuitive: Easy to model real world
- Encapsulation: Data protection and hiding
- Reusability: Code reuse through inheritance
- Large systems: Good for structuring complex systems
OOP Disadvantages
- State management: Bugs from object state changes
- Testing difficulty: Complex with many dependencies
- Parallel processing: Concurrency issues with shared state
FP Advantages
- Predictable: Pure functions always return same result
- Easy testing: Simple testing without side effects
- Parallel processing: No concurrency issues with immutability
- Debugging: Easy to track state changes
FP Disadvantages
- Learning curve: Difficult concepts
- Performance: Memory usage from maintaining immutability
- Real-world modeling: Some domains more natural with OOP
When to Use Each
Choose OOP for:
- Game development: Character, item-centric objects
- GUI applications: Buttons, windows components
- Simulations: Real-world modeling
- Large enterprise: Complex business logic
Choose FP for:
- Data transformation: Pipeline processing
- Async processing: Promise, async/await
- State management: Redux, Zustand
- Mathematical calculations: Algorithms, data analysis
Hybrid Approach
Modern JavaScript mixes both paradigms.
// React: OOP + FP hybrid
class UserProfile extends React.Component { // OOP: class
render() {
const { user } = this.props;
// FP: pure function, immutability
const fullName = [user.firstName, user.lastName]
.filter(Boolean)
.join(' ');
return <div>{fullName}</div>;
}
}
// Or functional component (more preferred)
const UserProfile = ({ user }) => {
const fullName = [user.firstName, user.lastName]
.filter(Boolean)
.join(' ');
return <div>{fullName}</div>;
};
| Comparison | OOP | Functional |
|---|---|---|
| Core Concept | Objects and State | Functions and Data |
| Data Mutation | Allowed (Mutable) | Not Allowed (Immutable) |
| Code Reuse | Inheritance | Function Composition |
| State Management | Internal object state | External state passing |
| Learning Difficulty | Easy | Difficult |
| Suitable Fields | UI, Games, Simulation | Data Processing, Parallel Processing |
There's no single answer. Choose based on situation, or mix both. JavaScript, Python, and other modern languages support multi-paradigm, allowing you to leverage the strengths of each paradigm.
