Use Object.freeze for easy immutability
Using immutable structures is one way for more defensive coding. This way you can be sure that no one else can modify your objects.
A good example is when you have a central place to set application-wide data, and you want to control how it is modified. (it's no coincidence that Redux heavily promotes immutability)
Basics
The simplest way is to use Object.freeze(obj)
which makes the parameter object immutable.
const obj = {prop: "property"};
const frozen = Object.freeze(obj);
Objects that are frozen can not be modified.
frozen.prop = "new";
console.log(frozen.prop); // property
The can not part is more tricky. In older execution environments, it silently fails, like in the example above. But it may throw an exception instead, for example in strict mode:
(() => {
"use strict";
try{
frozen.prop = "new";
}catch(e) {
console.log("Error"); // Error
}
})();
Use Object.isFrozen(obj)
to check whether a given object has been frozen.
console.log(Object.isFrozen(frozen)); // true
Caveats
Confusingly, Object.freeze
freezes the argument object and not just the result.
console.log(Object.isFrozen(obj)); // true
This is a side effect. Depending on the code, it might be better to copy the object before freezing. Use Object.assign({}, obj)
to achieve this.
const obj = {prop: "property"};
const frozen = Object.freeze(Object.assign({}, obj));
console.log(Object.isFrozen(frozen)); // true
console.log(Object.isFrozen(obj)); // false
Finally, Object.freeze
does not make the entire object tree immutable, think of it as a shallow freeze. If an object contains another object, the inner one is still mutable.
const obj = {
inner: {
prop: "property"
}
};
const frozen = Object.freeze(obj);
frozen.inner.prop = "new";
console.log(frozen.inner.prop); // new
Final remarks
Since frozen objects are drop-in replacements to normal objects, Object.freeze
is a great way of adding immutability to your project without adapting to a new API (which is the case for most libraries, for example, ImmutableJS)