
Have you ever heard something aboutimmutability? I'm mostly sure the answer isyes!, particularly on the programming ecosystem. Despite being a popular term, there are some misconceptions about the importance and principles of it. Let's dive in into it!
What does it mean?
Immutability is thestate of not changing, orbeing unable to be changed.
On a programming context, means that when we need tochange the state in our program, wemust create and track a new value rather than mutating the existing one.
🚨 This does not mean we can't have values that change over the lifecycle of our program. That's a common misconception about immutability 🖐
Immutable 🆚 Mutable
To understand the difference between both, take a look at the following example. Imagine that we have a shopping cart 🛒object
, that contains two properties,id
andtotal
.
constshoppingCart={id:'69zd841',total:0}
Let's say that we want to update thetotal
property of ourshoppingCart
, how can we achieve this?
Clone and update
Using thespread operator we can create a new object cloning the previous cart and updating thetotal
property, while preserving our original object in a pristine condition.
{...shoppingCart,total:15}
Mutate
Through theobject property accessor we can perform a modification to our original object.
cart.total=15
Thedifference between those two examples is that on the first one we preserved our original shopping cart and we created a new one and on the second one weoverwrited the value of thetotal
property.
The benefits
Now that we understood the concept of immutability and the difference between mutable 🆚 immutable data, let's see the benefits of applying it.
Immutability is like a seatbelt, it won't prevent an accident but it saves your life when it does
Predictability
Predictable code is code where you cananticipate the outcome with a single read. Mutation hides change, as we've seen before, the source is lost. Hidden change creates unexpected side effects that can cause complex bugs 🐛.
When we can predict the outcome, we start to feel more confident with our code simplifying our thought process. This helps us reason easier about our program.
Tracking mutations
When you mutate data, you're overwriting the same reference every time that you update something as we've pointed on the first example. Then it's impossible to have a track of the changes you've done to the program state.
Immutable data gives you a clear history of state to the program, because you're creating a new reference based on the source.
The drawbacks
Whenever we start creating new values such asArray
,Object
etc, instead of mutating existing ones the next question always is is:What kind of impact has this for performance?.
Performance
Avoiding mutations has acost that's correct, every time we have to reallocate a new value, that's consumingCPU time andmemory, including thegarbage collection process for values that are no longer referenced.
Is that anacceptable trade-off?It depends. We need somecontext to answer that question, for example:
If you have a single state change, that happens a few times on the lifecycle of your program, creating a new object, is certainly not a problem. It won't have no practical impact on the performance of the app. Compared to the time you will save not having to track and fix bugs caused by side effects, the winner clearly is immutability 🎉
Again, if that state change is going to occur frequently, or it happens in a critical path of your app, then performance is a totally valid concern 👍
Thankfully, there are some libraries out there that will provide performance optimizations such asImmutable.js andseamless-immutable.
Immutable data in JS
Constants
A constant is avariable thatcannot be reassigned andredeclared. This is an important concept to understand, because it does not mean the value it holds is immutable.
The use ofconst
tells the human being who's reading your code that the following variable won't be reassigned or redeclared. It's a great improvement incode readability because we're intentionally communicating that.
constfruits=['🍌','🍓','🥥']// We can't reassign the constant// ❌ TypeError: Assignment to constant variable.fruits=['🍏']// We can't redeclare the constant// ❌ SyntaxError: Identifier 'fruits' has already been declaredconstfruits=['🥝']// ✅ We can mutate the value as we want// fruits -> ['🍌','🍓', '🥥', '🍍']fruits.push('🍍')
Spread syntax
Also known as...
, it's a useful operator for cloningiterables such asArray
orObject
.
constfruits=['🍌','🍓','🥥']constshoppingCart={id:'69zd841',total:0}// Add a some fruits to the end of the arrayconstfruitsCollection=[...fruits,'🍍','🥝']// Update the shoppingCart total and clone all the other propertiesconstshoppingCartWithTotal={...shoppingCart,total:15}
Object.freeze
TheObject.freeze
function is a simple way to turn a mutableObject
orArray
into an "immutable value". This function freezes the object 🥶 you pass as argument.
But what doesfrozen object means? Afrozen object is an Object whose properties/indices has been marked as read-only and non-reconfigurable, so they can't be reassigned and the Object itself is marked as non-extensible, so no new properties can be added.
The freezing process ❄️ is only made at thetop level of the object. If you want to make your whole object immutable, make sure you deepfreeze each subObject
orArray
🤓.
constfruits=Object.freeze(['🍌','🍓','🥥'])constshoppingCart=Object.freeze({id:'69zd841',total:0,products:[]})// We can't extend the fruits Array// ❌ TypeError: Cannot add property N, object is not extensiblefruits.push('🍏')// ❌ We can't mutate shoppingCart top-level properties// shoppingCart -> { id: '69zd841', total: 0, products: [] }shoppingCart.total=123// 🚨 We can mutate shoppingCart objects// shoppingCart -> { id: '69zd841', total: 0, products: [{ name: 'Beer' }] }shoppingCart.products.push({name:'Beer'})
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse