π 3.1.0.5 Immutability
Immutability is an essential part of functional programming. If something is immutable, it cannot change. Conversely, if something is mutable, it can be changed.
In functional programming, instead of changing existing data, we create new data with our desired changes. This makes code more predictable and prevents bugs.
Immutability with Variablesβ
Let's start with a simple example. Here's the mutable approach:
let x = 1;
x = x + 2; // Changing x
Here's the immutable approach:
const x = 1;
const newX = x + 2; // Creating a new value
Why does this matter? In a large codebase, if you see let x, you know x might change somewhere else in the code. This makes the code harder to reason aboutβyou can't be sure what x is at any given moment. With const x, you know the value will never change. It's predictable.
From now on, prefer const over let whenever possible. This is the first step toward writing immutable code.
The Problem with Arraysβ
This is where immutability gets trickier. Arrays are reference types, which means even with const, you can still modify their contents:
const numbers = [1, 2, 3];
numbers.push(4); // This works! The array mutates
console.log(numbers); // [1, 2, 3, 4]
Wait, didn't we use const? Yes, but const only prevents reassignment (you can't do numbers = [5, 6, 7]). The array itself can still be modified.
Array Methods That Mutateβ
These array methods change the original array:
const numbers = [1, 2, 3];
numbers.push(4); // Adds to end β [1, 2, 3, 4]
numbers.pop(); // Removes from end β [1, 2, 3]
numbers.unshift(0); // Adds to beginning β [0, 1, 2, 3]
numbers.shift(); // Removes from beginning β [1, 2, 3]
numbers[0] = 99; // Changes an element β [99, 2, 3]
numbers.splice(1, 1); // Removes elements β [99, 3]
numbers.sort(); // Sorts in place
numbers.reverse(); // Reverses in place
Array Methods That Don't Mutateβ
These array methods return new arrays and leave the original unchanged:
const numbers = [1, 2, 3];
numbers.map(n => n * 2); // Returns [2, 4, 6], original unchanged
numbers.filter(n => n > 1); // Returns [2, 3], original unchanged
numbers.concat([4, 5]); // Returns [1, 2, 3, 4, 5], original unchanged
numbers.slice(1); // Returns [2, 3], original unchanged
In functional programming, we prefer the second group.
The Problem with Objectsβ
Objects have the same issue:
const person = { name: 'Ada', age: 28 };
person.age = 29; // This works! The object mutates
console.log(person); // { name: 'Ada', age: 29 }
The object changed even though we used const. Again, const prevents reassignment but doesn't prevent mutation of the object's properties.
Why This Matters: A Bug Waiting to Happenβ
Consider this code:
const scores = [100, 95, 88];
function addBonus(scoreArray) {
scoreArray.push(10); // Adds bonus to the array
return scoreArray;
}
const newScores = addBonus(scores);
console.log(newScores); // [100, 95, 88, 10] - expected
console.log(scores); // [100, 95, 88, 10] - wait, what?!
We called a function to get "new scores," but it also changed our original scores array! This happens because arrays are passed by reference in JavaScriptβscoreArray and scores point to the same array in memory.
This is a bug waiting to happen. If other parts of our code rely on scores being unchanged, they'll break.
When you pass an array or object to a function, you're not passing a copyβyou're passing a reference to the same data in memory. Any changes the function makes affect the original.
const original = [1, 2, 3];
const reference = original;
reference.push(4);
console.log(original); // [1, 2, 3, 4] - both variables point to the same array!
The Solutionβ
So how do we work with arrays and objects without mutating them? We need techniques to create new arrays and objects with our desired changes, leaving the originals untouched.
In the next lesson, we'll learn about the spread operator, which is JavaScript's primary tool for working with arrays and objects immutably. You'll see how to:
- Add items to arrays without
push() - Remove items without
splice() - Update object properties without mutation
- Copy arrays and objects safely
Let's explore that next.