DEV Community

Cover image for Mutability and Immutability in JavaScript: A Developer's Guide
Priya Jha
Priya Jha

Posted on

Mutability and Immutability in JavaScript: A Developer's Guide

You've probably heard seasoned React developers recommend using the spread operator to copy an array rather than simply assigning it to a new variable. But have you ever wondered why? It all boils down to how JavaScript handles reference types and their mutability.

Understanding mutability and immutability isn't just a JavaScript quirkβ€Š-β€Šit's a foundational concept that can make or break your code's reliability, especially in frameworks like React.

In this article, we'll dive deep into what it means for data to be mutable or immutable in JavaScript. We'll start by exploring the differences between primitive and reference types, uncover how memory allocation affects their behavior, and learn practical ways to manage and preserve immutability in your code. Let's get started!

In JavaScript, data types are broadly categorized into primitive types and reference types. These categories determine how the data is stored in memory, how it behaves when copied, and whether it's mutable or immutable. Let's break it all down.

Primitive Data Types

Primitive types include: string, number, boolean, undefined, null, symbol, bigint

Memory Allocation for Primitives

Primitive data types are stored in the stack memory, which is designed for storing small, fixed-size data.

Here's how it works:

  • When you declare a variable with a primitive value, the value is stored directly in the stack.
  • The stack operates on a Last-In-First-Out (LIFO) principle, making it fast and efficient for these simple data types.

Memory allocation for Primitives (immutable)

Since primitives are immutable, changing one variable's value doesn't affect any copies. JavaScript doesn't modify the original value but instead creates a new value entirely.

Reference Data Types

Reference types include: object,array, function

Memory Allocation for References

Reference types are stored differently:
The stack holds the reference (or address) pointing to the location of the data.
The actual data is stored in the heap memory, which is used for larger, dynamic data.

Memory allocation for references (mutable)

Reference types are mutable, meaning their values can be changed without creating a new object. When you update a property of an object or an element in an array, you're modifying the data in the heap memory, and all variables sharing the same reference reflect the change.

How to Preserve Immutability

Mutability can be tricky to manage, especially when dealing with shared state or complex data structures. Here's how to keep things under control:

1. Use Object.freeze to Lock Data

Object.freeze prevents any modifications to an object

const obj = { name: "Alice" };
Object.freeze(obj);
obj.name = "Bob"; // Nope, this won't work!
console.log(obj.name); // "Alice"
Enter fullscreen mode Exit fullscreen mode

Heads-Up: Object.freeze only works on the top-level properties (shallow freezing). For nested objects, you'll need deep freezing.

2. Clone Objects to Avoid Shared References

Instead of directly modifying an object, create a copy and work with that.

Using the Spread Operator

const obj1 = { name: "Alice" };
const obj2 = { ...obj1 }; // Creates a new object
obj2.name = "Bob";
console.log(obj1.name); // "Alice" (unchanged)
Enter fullscreen mode Exit fullscreen mode

Using Object.assign

const obj1 = { name: "Alice" };
const obj2 = Object.assign({}, obj1);
obj2.name = "Bob";
console.log(obj1.name); // "Alice"
Enter fullscreen mode Exit fullscreen mode

Both approaches break the link between the original and the copy.

3. Deep Cloning for Nested Objects

If your object has nested properties, a shallow copy won't cut it. You'll need a deep clone, which you can achieve using libraries like Lodash or structured cloning:

const obj1 = { name: "Alice", details: { age: 25 } };
const obj2 = JSON.parse(JSON.stringify(obj1)); // Deep clone
obj2.details.age = 30;
console.log(obj1.details.age); // 25
Enter fullscreen mode Exit fullscreen mode

Using const Doesn't Guarantee Immutability

Here's a common misconception: const doesn't make objects immutable. It only prevents reassignment of the reference, but the object's content can still change.

const obj = { name: "Alice" };
obj.name = "Bob"; // This works!
console.log(obj.name); // "Bob"
Enter fullscreen mode Exit fullscreen mode

If you want true immutability, you'll need to use techniques like freezing or always creating new objects.

Final Thoughts

Mutability and immutability might seem like abstract concepts, but they have a huge impact on your code's reliability and maintainability.

Primitives are immutable and copied by value.
Reference types are mutable and copied by reference.
To avoid unexpected side effects, use techniques like freezing, cloning, and immutability-focused patterns.

So the next time you see a React dev preaching about the spread operator, you'll know exactly why they're right. Keep coding and stay immutable when it counts! πŸ˜‰

Top comments (0)