const a = [0];
Object.freeze(a);
a[0] = 1;
function fail() {
"use strict";
a[0] = 1;
}
fail();
a.push(2);
The object being frozen is immutable. However, it is not necessarily constant. The following example shows that a frozen object is not constant (freeze is shallow).
const obj1 = {
internal: {},
};
Object.freeze(obj1);
obj1.internal.a = "aValue";
obj1.internal.a;
To be a constant object, the entire reference graph (direct and indirect references to other objects) must reference only immutable frozen objects. The object being frozen is said to be immutable because the entire object state (values and references to other objects) within the whole object is fixed. Note that strings, numbers, and booleans are always immutable and that Functions and Arrays are objects.
What is "shallow freeze"?
The result of calling Object.freeze(object)
only applies to the immediate properties of object
itself and will prevent future property addition, removal or value re-assignment operations only on object
. If the value of those properties are objects themselves, those objects are not frozen and may be the target of property addition, removal or value re-assignment operations.
const employee = {
name: "Mayank",
designation: "Developer",
address: {
street: "Rohini",
city: "Delhi",
},
};
Object.freeze(employee);
employee.name = "Dummy";
employee.address.city = "Noida";
console.log(employee.address.city);
To make an object immutable, recursively freeze each non-primitive property (deep freeze). Use the pattern on a case-by-case basis based on your design when you know the object contains no cycles in the reference graph, otherwise an endless loop will be triggered. An enhancement to deepFreeze()
would be to have an internal function that receives a path (e.g. an Array) argument so you can suppress calling deepFreeze()
recursively when an object is in the process of being made immutable. You still run a risk of freezing an object that shouldn't be frozen, such as window
.
function deepFreeze(object) {
const propNames = Reflect.ownKeys(object);
for (const name of propNames) {
const value = object[name];
if ((value && typeof value === "object") || typeof value === "function") {
deepFreeze(value);
}
}
return Object.freeze(object);
}
const obj2 = {
internal: {
a: null,
},
};
deepFreeze(obj2);
obj2.internal.a = "anotherValue";
obj2.internal.a;