Open In App

Why is Immutability so Important in JavaScript?

Last Updated : 13 Jun, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Why is immutability so important in JavaScript?

What’s wrong with mutability or mutating the objects in code?

Doesn’t it make things simple?

Before we go in-depth of understanding the importance of immutability we should first understand the concept of mutability and immutability in software development.

A princess kisses a frog hoping it will turn into a handsome prince. The concept of immutability says that a frog will always be a frog. The immutability concept is mainly originated from functional and object-oriented programming. Whenever we want to make changes to some data (for example to an object or an array) we should get a new object back with the updated data instead of directly modifying the original one.  

Why-is-Immutability-so-Important-in-JavaScript

Think of immutability as “save as” because you know it returns a newly changed object while traditional in-place mutation would be like “save” means updating the original and letting go of an earlier state. The structure of the immutable data cannot be changed.

The data would be the original one and once the object is created we can not modify its state in an immutable object. Consider the immutability concept as the human body which is not affected by the outside world. A state with peace of mind. 

immutability

The concept of mutation is vice versa. Mutability describes whether the state of an object can be modified after it’s declaration or not. Consider it as kissing frog results in the transformation of a prince. Take an example that we have a variable, and we assign a value to it. Later if we need to modify the value of this variable, and we change it then changing its state, the object is considered to be mutable.

Developers who never worked with the concept of immutability may get confused with it assigning a variable to a new value or reassignment. In JavaScript String and Numbers are immutable data types. 

JavaScript is not a good language to work with data in an immutable fashion. In JavaScript Arrays and Objects are not immutable. Their values can be changed over time. Both are always passed as a reference and the vast majority of available methods mutate data in place. You can consider the example given below…

Example: Sort array method

Javascript




const a = [2, 1, 4, 3];
console.log(a);
 
const b= a.sort();
 
console.log(b);
console.log(a)


Output:
[2, 1, 4, 3]
[1, 2, 3, 4]
[1, 2, 3, 4]

We have assigned an array to variable “a” and we are performing the sorting operation on it. The sorted array is assigned to variable “b” and you can see that we are getting the sorted array for both the variables after performing the sorting operation. Here objects and arrays are passed as a reference instead of copying over both variables “a” and “b” point to the same array in memory and that array was directly mutated by the method sort. 

A lot of array methods are the Mutator method. copyWithin, fill, pop, push, reverse, shift, sort, splice, unshift all these methods allows mutability. slice, from, map and filter are immutable because it creates a new array without mutating the original array. Object method which are immutable are object.assign.

 To make objects and arrays immutable you can use some techniques in JavaScript and create new values without modifying the original content. Do not change the original value of an object directly. Treat this object as immutable and return a completely new object with the updated value.

spread operator is useful mutating the array and objects because it iterates over values and  permits copying the properties of existing values into the new value .

Let’s understand this concept with one more example. We have an array of data that contains the number of days one employee worked on some project.

Example: slice and sort array method

Javascript




var daysWorked = [7, 7, 5, 9, 8, 6, 6, 7, 9, 5];
 
console.log(daysWorked);
 
//slice for 6 days work
var lastSixMonths = daysWorked.slice(0,6);
console.log(daysWorked)
console.log(lastSixMonths);
 
 
// let's sort the days worked
//mutable object
var sortedDaysWorked = daysWorked.sort();
 
console.log(sortedDaysWorked);
console.log(daysWorked)
 
//slice for seven days work
var lastSevenMonths = daysWorked.slice(0,7);
 
console.log(lastSevenMonths);
console.log(daysWorked)


[
7, 7, 5, 9, 8,
 6, 6, 7, 9, 5]
[
7, 7, 5, 9, 8,
 6, 6, 7, 9, 5
]
[ 7, 7, 5, 9, 8, 6 ]
[
5, 5, 6, 6, 7,
 7, 7, 8, 9, 9
]
[
5, 5, 6, 6, 7,
7, 7, 8, 9, 9]
[
5, 5, 6, 6,
7, 7, 7
]
[
5, 5, 6, 6, 7,
 7, 7, 8, 9, 9]

In the above method, we have used two methods on variable daysWorked. 

  • Slice: In the above example we are achieving immutability using the slice method. This method slices the original object and instead of modifying the original dataset, we are getting the new copy of the object lastSixMonths.
  • Sort: This method is a mutable way and it is sorting the original dataset. This method is preventing us to make further calculations on the dataset.

Example: assign object method

Javascript




const GFG = {
  article:"javascript",
  date:"30/05/2022"
}
 
const gfg1=GFG
gfg1.article="react";
 
console.log(gfg1);
console.log(GFG);
 
gfg2=Object.assign({},gfg1);
gfg2.article="typescript";
 
console.log(gfg2);
console.log(gfg1);
console.log(GFG);


Output:

{ article: 'react', date: '30/05/2022' }
{ article: 'react', date: '30/05/2022' }
{ article: 'typescript', date: '30/05/2022' }
{ article: 'react', date: '30/05/2022' }
{ article: 'react', date: '30/05/2022' }

Object.assign is a method which takes  argument , empty object and source object (the object which have to be copied) . so  here gfg1 object properties copied in empty object argument of gfg2 without mutating gfg1 object.

Example: spread operator

Javascript




const GFG = {
  article:"javascript",
  date:"30/05/2022"
}
 
const gfg1=GFG
gfg1.article="react";
 
console.log(gfg1);
console.log(GFG);
 
//spread operator create new reference
gfg2= {...gfg1}
gfg2.article="typescript";
 
console.log(gfg2);
console.log(gfg1);
console.log(GFG);


Output:

{ article: 'react', date: '30/05/2022' }
{ article: 'react', date: '30/05/2022' }
{ article: 'typescript', date: '30/05/2022' }
{ article: 'react', date: '30/05/2022' }
{ article: 'react', date: '30/05/2022

Importance of Immutability in JavaScript

What is the good part of the immutability? Why do we need to care about the immutability in the first place? Why even bother?

Immutability gives stricter control over your data immediately making your code safer and more predictable. In other words, immutable objects allow you to control the interface and data flow in a predictable manner, discovering the changes efficiently. It also makes it easier to implement complex features such as undo/redo, time travel debugging, optimistic updates and rollback, and so on. 

If we talk about the frontend library React, Vue os state management library Redux then immutability can also help achieve better performance by enabling quick and cheap comparisons between versions of the state before and after changes. Components can take advantage of this and intelligently re-render itself only when needed. This can significantly boost performance. 

The main benefits of immutability are predictability, performance, and better mutation tracking.

1. Predictability

In any application when we work on some front-end libraries, we declare a lot of state in it. We perform the asynchronous action and it updates the original state (mutation). Once the end-user starts using it the updated state will be significantly different from the initial state. Mutating the state hides changes and it creates side effects that can cause several bugs. Debugging becomes hard in such cases.

When you keep your application architecture immutable and mental model simple it becomes easier to predict the data in the state at any given time and then you can rest assured that it won’t create any nasty side effects. 

2. Performance

Creating an immutable object cost memory. How? When you add value to an immutable object you need to create a new object and in this new object, you copy the existing value with the new value which requires additional memory. To reduce memory consumption we use structural sharing.

Whatever update we make it returns new values, but we share the structures internally to reduce memory consumption. For example, if you append to a vector with 100 elements, it doesn’t create a new vector 101 elements long. Only a few small objects are allocated internally.

3. Mutation Tracking

One of the advantages of immutability is that you can optimize your application by making use of reference and value equality. This makes it easy to identify if anything has changed. You can consider the example of state change in the React component. shouldComponentUpdate can be used to check if the state is identical comparing the state object and preventing it from unnecessary rendering. 

Immutability allows you to track the changes that happen to these objects like a chain of events. Variables have new references that are easy to track compared to existing variables. This helps in debugging the code and building the concurrent application. Also, event debuggers help you to replay DOM events with video playbacks that work on tracking mutation. 

For the first time, the concept of immutability might be confusing for you. You can do better if you understand the need and benefits of immutability. When the state is mutated you bump into many errors and dealing with it makes you much better in understanding the concept of immutability. 



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads