Mutable and Immutable in JavaScript
This article explains mutable and immutable concepts in JavaScript.
YouTube Video
Mutable and Immutable in JavaScript
What is Mutable?
Mutable means that a value can be modified. Objects and arrays, which are reference types, are typical examples of mutable data structures.
Example of a Mutable Object
1let person = { name: "Alice", age: 25 };
2person.age = 26;
3console.log(person); // { name: "Alice", age: 26 }
In this code, the age
property of the person
object is changed from 25
to 26
. Since objects are passed by reference, the content at the memory address stored in the person
variable is modified.
Example of a Mutable Array
1let numbers = [1, 2, 3];
2numbers.push(4);
3console.log(numbers); // [1, 2, 3, 4]
In this code, the push
method is used to add a new element 4
to the original array. This modifies the original array, making it a mutable operation.
Example in a Function
1// Function to append a value to an array
2function append(arr, value) {
3 arr.push(value); // Modify the original array
4 console.log(arr);
5}
6
7let numbers = [1, 2, 3];
8append(numbers, 4);
9
10console.log(numbers); // [1, 2, 3, 4] (original array is modified)
When performing mutable operations inside a function, the original array is also modified.
What is Immutable?
Immutable means that a value cannot be modified. Primitive types are fundamentally immutable.
Example of an Immutable Primitive Type
1let str = "hello";
2str[0] = "H";
3console.log(str); // "hello"
Attempting to change the first character of the string str
to H
fails because strings are immutable.
Example in a Function
1// Function to increment a number
2function increment(num) {
3 num++; // This modifies only the local copy of num
4 console.log(num);
5}
6
7let number = 10;
8increment(number);
9
10console.log(number); // 10 (original number remains unchanged)
Since numbers are immutable, operations inside a function do not affect the original variable.
Immutable Operations on Arrays
Arrays are mutable, but creating a new array instead of modifying the original one allows for immutable operations.
1// Create an array of numbers
2let numbers = [1, 2, 3];
3
4// Create a new array by spreading the original and adding a new element
5let newNumbers = [...numbers, 4];
6
7console.log(numbers); // [1, 2, 3] (original array is unchanged)
8console.log(newNumbers); // [1, 2, 3, 4] (new array with an added element)
Here, the spread syntax (...
) is used to create a new array newNumbers
. Since the original numbers
array is not modified, this is an immutable operation.
Benefits of Using Immutable Data Structures
Improved Predictability
Since immutable data cannot be changed, unexpected modifications are less likely, reducing the risk of bugs.
Compatibility with Libraries Based on Immutability
Libraries like React
and Redux
are often designed with immutable data in mind, making state management easier when used correctly.
Making Objects Immutable with Object.freeze
Object.freeze
can be used to prevent modifications to an object.
1// Create a frozen object (properties cannot be modified)
2const person = Object.freeze({ name: "Alice", age: 25 });
3
4// Attempt to modify a property (ignored in non-strict mode, error in strict mode)
5person.age = 26;
6
7console.log(person); // { name: "Alice", age: 25 }
However, Object.freeze
performs a shallow freeze, meaning that properties of nested objects remain mutable.
1// Create a frozen object with a nested object
2const user = Object.freeze({ profile: { name: "Bob" } });
3
4// Attempt to modify a nested property (this works because Object.freeze() is shallow)
5user.profile.name = "Charlie";
6
7console.log(user.profile.name); // "Charlie" (nested object is still mutable)
To create a fully immutable object, a deep freeze is required.
1// Function to deeply freeze an object, making all nested objects immutable
2function deepFreeze(obj) {
3 Object.keys(obj).forEach(key => {
4 if (typeof obj[key] === "object" && obj[key] !== null) {
5 deepFreeze(obj[key]); // Recursively freeze nested objects
6 }
7 });
8 return Object.freeze(obj); // Freeze the top-level object
9}
10
11// Create a deeply frozen object
12const user = deepFreeze({ profile: { name: "Bob" } });
13
14// Attempt to modify a nested property (ignored)
15user.profile.name = "Charlie";
16
17console.log(user.profile.name); // "Bob" (unchanged due to deep freeze)
Summary
- Mutable data can be modified, including objects and arrays.
- Immutable data cannot be modified, including primitive types such as strings and numbers.
- Using spread syntax or
map
enables immutable data operations.. Object.freeze
anddeepFreeze
can be used to prevent modifications to objects.- Using immutable data allows for more predictable and less error-prone code.
Immutable design enhances code safety and readability, so make good use of it!
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.