Profile Picture

How to Avoid Array Mutation

In this article, I'll focus on showing how to add, edit and remove items in an array causing mutation and non-mutation ways.

Some things we need to keep in mind when writing code avoiding mutation is to return a new one after the update.

It's a common approach when working with functional programming and if you want to understand some concepts of functional programming I recommend you read this article I wrote some time ago.

Why Avoid Mutation

When you work with immutable data you can have some positive impacts like the following:

  • Track data without mutation is pretty better;
  • The immutable state helps you implement unidirectional data flow that helps you to handle data;

I really recommend you read this article go deeper into why avoid mutation.

Causing Mutation

Causing Mutation

The following steps will cause mutation into the array adding, removing and editing elements from family.

To mutate we'll use the following array:

const heroesMutate = ["Spider-man", "Thor", "Hulk", "Iron Man"];
console.log(heroesMutate); // => ["Spider-man", "Thor", "Hulk", "Iron Man"]

Including

Methods will be used:

See the following use-case examples for these methods:

heroesMutate.push("Captain Marvel");
console.log(heroesMutate); // => ["Spider-man", "Thor", "Hulk", "Iron Man", "Captain Marvel"]

heroesMutate.unshift("Deadpool");
console.log(heroesMutate); // => ["Deadpool", "Spider-man", "Thor", "Hulk", "Iron Man", "Captain Marvel"]

heroesMutate.splice(2, 0, "Black Panther");
console.log(heroesMutate); // => ["Deadpool", "Spider-man", "Black Panther", "Thor", "Hulk", "Iron Man", "Captain Marvel"]

Editing

The following case will find index for the element we want to edit and set value to the found index:

const heroesMutate = ["Spider-man", "Thor", "Hulk", "Iron Man"];
const indexDeadpool = heroesMutate.indexOf("Deadpool");
heroesMutate[indexDeadpool] = "Wolverine";

console.log(heroesMutate); // => ["Wolverine", "Spider-man", "Black Panther", "Thor", "Hulk", "Iron Man", "Captain Marvel"]

Removing

Methods will be used:

See the following use-case examples for these methods:

heroesMutate.pop();
console.log(heroesMutate); // => ["Wolverine", "Spider-man", "Black Panther", "Thor", "Hulk", "Iron Man"]

heroesMutate.shift();
console.log(heroesMutate); // => ["Spider-man", "Black Panther", "Thor", "Hulk", "Iron Man"]

heroesMutate.splice(1, 1);
console.log(heroesMutate); // => ["Spider-man", "Thor", "Hulk", "Iron Man"]

Avoiding Mutation

Avoiding Mutation

In this topic, we'll take the steps of add, remove and edit avoiding mutations.

Methods will be used:

See the following use-cases:

const villains = ["Loki", "Thanos", "Venom", "Abomination"];
console.log(typeof villains === "object"); // => true

Perhaps you're wondering, does Object.freeze() work in an array? And the answer is yes because in Javascript array are type object, you can check this with the following example:

Including

Add to the end of array:

const villains = ["Loki", "Thanos", "Venom", "Abomination"];
const newVillains = villains.concat("Juggernaut");
const newVillains2 = [...newVillains, "Magneto"];
const newVillains3 = ["Red Skull", ...newVillains2];

console.log(villains); // => ["Loki", "Thanos", "Venom", "Abomination"]
console.log(newVillains); // => ["Loki", "Thanos", "Venom", "Abomination", "Juggernaut"]
console.log(newVillains2); // => ["Loki", "Thanos", "Venom", "Abomination", "Juggernaut", "Magneto"]
console.log(newVillains3); // => ["Red Skull", "Loki", "Thanos", "Venom", "Abomination", "Juggernaut", "Magneto"]

In the following example we'll add Ultron after Thanos in the array:

const newVillains = [
  ...villains.slice(0, 2),
  "Ultron",
  ...villains.slice(2, villains.length),
];

console.log(villains); // => ["Loki", "Thanos", "Venom", "Abomination"]
console.log(newVillains); // => ["Loki", "Thanos", "Ultron", "Venom", "Abomination"]

Editing

In the following example we'll edit Venom to Galactus:

const indexVenom = villains.indexOf("Venom");
const newVillains = [
  ...villains.slice(0, indexVenom),
  "Galactus",
  ...villains.slice(indexVenom + 1),
];
const newVillains2 = newVillains.map((v) =>
  v === "Abomination" ? "Ultron" : v
);

console.log(villains); // => ["Loki", "Thanos", "Venom", "Abomination"]
console.log(newVillains); // => ["Loki", "Thanos", "Galactus", "Abomination"]
console.log(newVillains2); // => ["Loki", "Thanos", "Galactus", "Ultron"]

Removing

In the following example we'll remove Thanos from the array:

const indexThanos = villains.indexOf("Thanos");
const newVillains = [
  ...villains.slice(0, indexHelder),
  ...villains.slice(indexHelder + 1),
];
const newVillains2 = newVillains.filter((v) => v !== "Thanos");

console.log(villains); // => ["Loki", "Thanos", "Venom", "Abomination"]
console.log(newVillains); // => ["Loki", "Venom", "Abomination"]
console.log(newVillains2); // => ["Loki", "Abomination"]

See that in all the examples that we developed above, a new instance of the array is created, thus avoiding the mutation of the initially defined arrays.


Wrapping Up

Avoiding mutations is a safe and non-return path.

When you realize that you're writing code observing this type of detail, believe me, you will be writing a better, secure and avoiding possible bugs due to mutation.

Feel free to share your feedback and experience in the comments.

Enjoy programming! ✨

References