Skip to main content Accessibility Feedback

The challenge with immutable objects and arrays in vanilla JS

Last year, I wrote a bit about immutability.

What is immutability?

In JavaScript, when you assign an existing array or object to a new variable, it does not create a new array or object with the same properties. Instead, it creates a reference to the original.

var sandwiches = ['turkey', 'tuna', 'ham', 'pb&j'];
var moreSandwiches = sandwiches;

// logs ['turkey', 'tuna', 'ham', 'pb&j']
console.log(moreSandwiches);

// Remove "tuna" from sandwiches
sandwiches.splice(1, 1);

// logs ['turkey', 'ham', 'pb&j']
console.log(moreSandwiches);

When working with array and object data, it’s important to create immutable copies before manipulating them. An immutable array or object is a unique copy of the original that, when manipulated, does not affect the original.

A few common but incomplete options

I also shared a few approaches for creating immutable copies with vanilla JS.

You can use Object.assign() to create a new object, and Array.slice() or Array.from() to create a copy of an array.

// Copy an object
var clonedObj = Object.assign({}, originalObj);

// Copy an array
var clonedArr1 = originalArr.slice();
var clonedArr2 = Array.from(originalArr);

You can also stringify and then parse and object or array as a catchall for both types.

var clone = JSON.parse(JSON.stringify(orig));

My buddy Andrew Borstein found problems with all of these methods.

The Object.assign(), Array.slice(), and Array.from() methods all create shallow copies. If an object has arrays in it, or an array has objects in it, those are not immutable copies.

// Copy an object
var clonedObj = Object.assign({}, originalObj);

// Update the copy
// This will also update the value in the original
clonedObj.arr[3] = 'new value';

The stringify() and parse() trick avoids this issue, but only works for valid JSON values. Functions and certain other values are not copied over.

Tomorrow, we’ll look at a strategy for creating deep immutable copies with vanilla JS.