According to (wikipedia)[https://en.wikipedia.org/wiki/Immutable_object] an immutable object (unchangeable object) is an object whose state cannot be modified after it is created. This rule is quite simple, if you want to modify some property of an object you have to do it on a copy. We will see a bit later what improvements and fancy features it unlocks for our developments.
EcmaScript provides utilities to keep our data immutable. Arrays and objects APIs contain methods to create copies and even prevent instances from being updated. More recently EcmaScript introduced a new syntaxes to create copies of objects and arrays.
We want to add a name property in our object.
We can do it with
Object.assign and a little trick. Basically it copies all properties from an object into another one, thus it mutates the target object. We use a small trick, passing an empty object as first parameter, which creates a new reference.
We now have a new object with our new
name property and a
commonNames property remain unchanged. With this method you can create/overwrite multiple properties at the same time.
Now let's do it with an array. We want to add two new elements in an array in an immutable way.
Array.concat does not mutate our array. Instead, it returns a new array.
This method is flexible. It takes as many elements as you want. They can be either values or arrays.
Object.freeze isn't really familiar. It lets you make an object immutable! It prevents every type of mutation (creation, modification, deletion) induced by the use of setters.
We will try to delete
name property after object has been frozen.
Reallocation isn't necessary since the object passed as parameter has been made immutable by
Object.freeze. This method has two available modes:
- A non-strict mode that does not apply mutations
- A strict mode that throws a
TypeErrorif you try to apply mutations
Be careful, it is not recursive. Our property
commonNames isn't immutable.
The spread operator syntax has been introduced in ES2015 for arrays and in ES2018 for objects. It copies all properties of a given object into a new object literal.
With arrays, it copies all values of an array into a new array.
it replaces nicely
concat, it is easily readable and creates a convention between arrays and objects. It is possible to spread multiple arrays and objects in a same literal.
Why use immutability?
Functional programming’s goal is to allow us to think less and write more descriptive code.
It has a declarative approach of programming, which means that you focus on describing what your program must accomplish rather than how it should do it. It gives more meaning to your code so that the next developper can understand it more easily. Functional programming brings along other concepts that help reach this goal, such as immutability.
What are the benefits?
Does it sound like a hype term to you? Immutabilty brings many solutions to programming matters we ecounter everyday:
- Avoid side effects
- Data changes detection made simple (shallow comparison)
- Explicit data changes
- Memory optimization
- Better rendering performances
- Easy testing
In the last few years one of our biggest challenges has been to find an efficient way to detect changes in our data to determine whether or not we should render our interfaces. It's easy to detect changes between primitive values, but it's a completely different issue for objects and arrays. You could compare them by value but you would have to implement recursive algorithms and deal with potential issues like cyclical references. Another method would be to compare object references with the strict equality operator
===. It's more effective and there isn't any risk to enter in some deathly infinity loop. That's why modern frameworks enforce this concept.
Highlighted by modern frameworks/libraries
Modern frontend frameworks and libraries are based on a concept that improves drastically performances. This is the well-known Virtual DOM. This technology has been created from a simple evidence: DOM manipulations are expensive.
Like explained, frontend frameworks and libraries chose to use immutability in order to improve their performances. Nowadays we have to deal with more and more data in our applications, and therefore more markups. So our browsers need to handle much more computations than 10 years earlier. DOM operations are expensive, modern frameworks tend to reduce the number of DOM updates.
Why do we need utility libraries?
As we saw earlier, the way to handle immutability in EcmaScript is made simple thanks to syntactic sugar but is quite limited in nested structures. With the arrival of libraries like
redux, nested structures have become more popular.
As you can see it becomes more tedious to write and harder to read. Simple use-cases like overriding an index of an array aren't easily achievable.