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
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
In this topic, we'll take the steps of add, remove and edit avoiding mutations.
Methods will be used:
- Array.prototype.slice();
- Array.prototype.concat();
- Array.prototype.map();
- Array.prototype.filter();
- Spread syntax;
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! ✨