What does Object.freeze actually guarantee?
Freezing an object makes its own properties non-writable and non-configurable. That means you cannot add a new property, you cannot delete an existing one, and you cannot change the value or the attributes of an existing one. The freeze is enforced by the engine, so attempts to break it fail.
const settings = Object.freeze({ theme: "dark", nested: { font: "serif" } });
console.log(Object.isFrozen(settings)); // true
console.log(Object.isSealed(settings)); // true
try {
settings.theme = "light";
} catch (err) {
console.log(err.name); // "TypeError" in strict mode
}
console.log(settings.theme); // "dark"
// The freeze is shallow.
settings.nested.font = "sans";
console.log(settings.nested.font); // "sans" - the inner object is not frozenThere is a difference between strict and sloppy mode here that is worth mentioning. In strict mode, which includes every ES module and every class body, a failed assignment throws a TypeError, so you find out immediately. In sloppy mode the assignment fails silently and the object is unchanged, which is worse because the code carries on as though it worked.
Freezing also makes the object non-extensible and marks its properties as non-configurable. The isFrozen and isSealed checks report on that state, and the seal method does the weaker version, preventing additions and deletions but still allowing existing values to change.
Two things freeze does not do. It does not make the object deeply immutable, because it only touches the top level, and it does not affect the internal state of exotic objects. A frozen date still changes with setTime, and a frozen array still rejects new elements because the length property is frozen, but other built-ins keep their own behaviour.