Avoiding mutation with Shallow Copy
An approach to save you time and refactoring efforts
JavaScript is beautiful❤️🔥 but there is some caveats that you must know about, one of them is about mutation.
Let’s take a deeper dive on this effect and understand once for all what’s that all about on and how you can overcome this effect in an elegant way.
To illustrate the problems, most of the explanations will be covered with some clear examples that you can easily test on your side, even through your Browser’s console.
So enough chit-chat, let’s get straight to the point.
What’s precisely mutation?
Mutation
is an alteration of the existing value(s) from a data structure, like Object
, Array
, Function
, Map
, Set
, so on.
It happens every time you add
, remove
or modify
the initial data state.
Here is some examples of that:
Is there immutable data types?
Yes! All Primitives (primitive values and primitive data type) are immutable by nature, meaning that they cannot be altered.
Example:
The undesired mutation side-effects
As you probably could see, it’s very easy to mutate a data structure and this can easily introduce some undesired side effects, like:
- Surprises: your code is no longer deterministic but unpredictable.
- Lost of data reliability: your data is no longer reliable as you cannot be sure if it’s still pure.
- Increased maintainability cost: you have to spend more time to refactor/maintain your code just because you got surprises around the way.
- Bugs: well, this is the result of all the points above.
Let’s take a look on an real world undesired side-effect caused by mutation:
The method maskSensitivityInfos()
not only mutated the credit card number, introducing a new bug, but also broke the entire payment processing pipeline of the application; and I’m pretty sure that someone would be not reeeally happy about it.
Fixing mutation
This is a fairly easy task! All we got to do is to copy the Object.
This can be done either by using Spread Operator or Object.assign()
.
Tip: learn to take advantage of ES6 ‘spread operator’
With just a small tweak we not only fixed the example above but made it reliable again!
The only tricky part is, copy process can vary from data-structure to data-structure, example:
- Copy Array:
const copy = [ ...originalArray ]
- Copy Object:
const copy = { ...originalObject }
- Copy Date:
const copy = new Date(originalDate)
- Copy Map:
const copy = new Map(originalMap)
- Copy Set:
const copy = new Set(originalSet)
- so on…
To avoid those repetitive operations (code duplications) we can take advantage of the Shallow Copy
approach.
Shallow Copy
Shallow Copy
is a code utility that centralize all copy related operations into a single place and takes care of the different copy strategies required from the data structure.
This approach has some great benefits, like:
- Single source of truth.
- Low refactoring effort required.
- Reusability.
Just be aware that, as a shallow
operation, this only affects the first level of the structure, meaning that anything bellow the 1st level, will be unaffected.
This will generally satisfy almost all your needs, but in case you need to have a
deep
copy, you can easily update the code to include a recursive operation over its items 😉
Dependency
We will be using an improved version of the JavaScript typeof()
operator, which we covered here before, if you haven’t read it yet, click in the link bellow and check that out!