The Fundamentals of Immutability

Understand how Immutability works with Fullstackgada

âš ī¸ Mutable vs 🔒 Immutable Demo

The Mutation Problem: When we directly change the original data, unexpected side effects can occur!
Original User Object:
{ name: "Jethalal", city: "Mumbai", age: 45 }

Operation Results:

Click the button above to see mutation vs immutability in action...

💌 Love Letter Analogy

💔
Mutation: Like someone changing "I love you Babita" to "I love you Iyer" in my love letter!
💝
Immutability: Keep the original letter safe and write a new one!

🛒 Shopping Cart Example

Use Case: Why immutability is essential when adding items to a shopping cart.
Current Cart:
Empty Cart

📊 Cart History (Benefits of Immutability)

0
Empty cart state

đŸ’ģ Code Examples - Mutable vs Immutable

// ❌ Dangerous: Direct Mutation
let user = { name: "Jethalal", city: "Mumbai" };
let anotherRef = user; // Same object reference
user.city = "Delhi"; // Mutation!
// Problem: Both references affected!
console.log(user.city); // "Delhi"
console.log(anotherRef.city); // "Delhi" (Unexpected!)
// ❌ Array Mutation Problem
let cart = ["iPhone", "MacBook"];
let backupCart = cart; // Same reference
cart.push("iPad"); // Mutation!
console.log(backupCart); // ["iPhone", "MacBook", "iPad"]
// Original backup also changed!
// ✅ Safe: Immutable Object Update
let user = { name: "Jethalal", city: "Mumbai", age: 45 };
// Create new copy instead of mutating
let updatedUser = { ...user, city: "Delhi" };
console.log(user.city); // "Mumbai" (Original safe)
console.log(updatedUser.city); // "Delhi" (New copy)
// ✅ Using Object.assign()
let original = { name: "Babita", profession: "Teacher" };
let updated = Object.assign({}, original, { profession: "Doctor" });
console.log(original.profession); // "Teacher" (Safe)
console.log(updated.profession); // "Doctor" (New)
// ✅ Immutable Array Operations
let cart = ["iPhone", "MacBook"];
// Immutably add item
let newCart = [...cart, "iPad"];
// Immutably remove item
let filteredCart = cart.filter(item => item !== "MacBook");
console.log(cart); // ["iPhone", "MacBook"] (Original safe)
console.log(newCart); // ["iPhone", "MacBook", "iPad"]
console.log(filteredCart); // ["iPhone"]
// ✅ Immutably update array item
let users = [
{ id: 1, name: "Jethalal" },
{ id: 2, name: "Bhide" }
];
let updatedUsers = users.map(user =>
user.id === 1 ? { ...user, name: "Jethalal Gada" } : user
);
// ✅ Pure Functions (No Side Effects)
function addToCart(cart, item) {
return [...cart, item]; // Returns new array
}
function updateUser(user, updates) {
return { ...user, ...updates }; // Returns new object
}
// Usage
let cart = ["iPhone"];
let newCart = addToCart(cart, "MacBook");
// Original cart unchanged!
// ✅ Reducer Pattern (Redux Style)
function cartReducer(state, action) {
switch(action.type) {
case 'ADD_ITEM':
return { ...state, items: [...state.items, action.item] };
case 'REMOVE_ITEM':
return { ...state, items: state.items.filter(item => item.id !== action.id) };
default:
return state; // Always return state
}
}

âš–ī¸ Immutability: Benefits vs Trade-offs

Aspect ✅ Benefits âš ī¸ Trade-offs
Predictability No unexpected side effects, easier debugging Code can be more verbose, extra copying
Time Travel Undo/Redo features, track state history Increased memory usage with history
Concurrency Thread-safe, no race conditions Performance overhead for deep copying
Testing Easier to test pure functions Need to test immutable patterns correctly
Performance Structural sharing, memoization possible Initial performance cost for copying