Kishore Patra
May 17, 2020

Mutate object or arrays without changing original source in javascript

rctx-contextmenu Photo by Luca Micheli on Unsplash

If you are building javascript application irrespective of any framework, you would have faced a specific issue where you want to modify an Object or Array, but with modification, the original value also updating, but you don't want to update the original value.

That's where an immutability helpers libraries help us. I personally prefer Immutability Helper library to handle this but there are others like Immutable JS, which is also a great library.

In this post, I will be discussing the Immutability Helper library and will try to cover most of the features like push, splice, merge, etc.

Prerequisites

Before starting I would like you to go through MDN specification regarding data types and data structures which will give you a fair idea on various kinds of data types and data structures in JS.

The problem

const originalObj = {
  name: 'Volkswagen',
  color: 'red'
}

const newObj = originalObj;

newObj.color = 'green';

console.log(newObj.color); // green
console.log(originalObj.color); // green

The above example looks strange because I have changed newObj color value but originalObj color value also got the changes. This weird thing is happening because in Javascript Object and Array are reference types, that means if you are creating an object or array in one place and then assigning that value to another variable it takes only one memory allocation. So if you are changing any property value of newObj which has a reference value of originalObj, that means you are changing in only one place. This happens the same for Arrays as well.

More on this you can find here.


Now coming to our main focus are which is how to make object or arrays immutable using Immutability Helper library.

To use Immutability Helper you have to first install it by running the below command

npm install immutability-helper --save

and import it wherever you want to use

import update from 'immutability-helper';

Below are some of the commands which we can use

$push

push() all the items in array on the target

Example:

const initialArray = [1, 2, 3];
const newArray = update(initialArray, {$push: [4]});

console.log(initialArray); // [ 1, 2, 3 ]
console.log(newArray); // [ 1, 2, 3, 4 ]

$splice

For each item in arrays call splice() on the target with the parameters provided by the item

Nested array push example:

const collection = [1, 2, {a: [12, 17, 15]}];
const newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});

console.log(collection); // [ 1, 2, { a: [ 12, 17, 15 ] } ]
console.log(newCollection); // [ 1, 2, { a: [ 12, 13, 14, 15 ] } ]

Remove array element example:

const obj = {items: [1, 2, 3, 4]};
const index = 2;
const newObj = update(obj, { items: { $splice: [[index, 1]] } });

console.log(obj); // { items: [ 1, 2, 3, 4 ] }
console.log(newObj); // { items: [ 1, 2, 4 ] }

$apply

Passes in the current value to the function and updates it with the new returned value

const obj = {a: 5, b: 3};
const newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});

console.log(obj); // { a: 5, b: 3 }
console.log(newObj); // { a: 5, b: 6 }

$set

Replace the target entirely

Simple example:

const obj = {a: 5, b: 3};
const newObj = update(obj, {b: {$set: obj.b * 2}});

console.log(obj); // { a: 5, b: 3 }
console.log(newObj); // { a: 5, b: 6 }

Example with computed property names:

const collection = {children: ['zero', 'one', 'two']};
const index = 1;
const newCollection = update(collection, {children: {[index]: {$set: 1}}});

console.log(collection); // { children: [ 'zero', 'one', 'two' ] }
console.log(newCollection); // { children: [ 'zero', 1, 'two' ] }

$merge

Merge the keys of an object with the target

const obj = {a: 5, b: 3};
const newObj = update(obj, {$merge: {b: 6, c: 7}});

console.log(obj); // { a: 5, b: 3 }
console.log(newObj); // { a: 5, b: 6, c: 7 }

There are other 2 advanced features. One is Autovivification and another one is Adding your own commands. You can check out those from their respective docs.

Conclusion

There are other libraries that solve immutability in a great way. I personally know about immutable-js, which is great in its own way. You can try both and find which suits your project best. I personally used Immutability Helper multiple times and thus I'm comfortable with this library. You can try whatever you want.

Thanks for reading!

Let me know what your thought on this post by messaging me on twitter or linkedin.