All topics
Objectsintermediate

Object.freeze, seal, and Immutability Patterns

Built-in methods for restricting how much an object can be changed, and why true deep immutability requires more than a single call.

Three levels of restriction, all shallow.

Object.freeze is like laminating the cover page of a document — the cover itself can't be altered anymore, but if the cover references a separate folder full of loose pages (a nested object), those loose pages are still completely free to be rewritten unless you laminate every single page inside that folder too.

Key Concepts

1
    Object.preventExtensions(o)   no new properties
    Object.seal(o)                no new, no delete; existing
                                  ones still writable
    Object.freeze(o)              no new, no delete, no change
2
And freeze only reaches one level.
    const o = Object.freeze({ a: 1, nested: { b: 2 } });
freeze
3
    o.a = 99;            // ignored (throws in strict mode)
    o.nested.b = 99;     // works -- nested is a different object
4
That is the thing to know. freeze freezes the object, not the graph.
freeze
5
A deep freeze is recursive.
    function deepFreeze(o) {
      Object.values(o).forEach(v => {
        if (v && typeof v === 'object') deepFreeze(v);
      });
      return Object.freeze(o);
    }
6
Watch for cycles, and note that freezing a large structure costs time and cannot be undone.
7
Silent versus loud failure.
    const o = Object.freeze({ a: 1 });
    o.a = 2;                  // sloppy: ignored. strict: TypeError
8
In a module or a class you are already in strict mode, so it throws — which is what you want, since a silent no-op is a bug you find much later.
9
Checking.
    Object.isFrozen(o)
    Object.isSealed(o)
    Object.isExtensible(o)
10
The pattern used in practice is not freezing — it is not mutating.
    // instead of mutating
    state.items.push(item);
11
    // produce a new value
    const next = { ...state, items: [...state.items, item] };
12
Redux, React state and every immutable update follow this. Freezing is a way to enforce it during development; the discipline is what actually delivers the benefit.
13
The new non-mutating array methods exist for the same reason:
14
    arr.toSorted()     instead of arr.sort()
    arr.toReversed()   instead of arr.reverse()
    arr.with(i, v)     instead of arr[i] = v
15
When freezing is worth the cost. Configuration objects and constants that must not be edited, and development-mode checks in a library. Freezing application state on every update is expensive and rarely justified — Object.freeze is not free.
16
What the interviewer is probing.1. "What is the difference between freeze and seal?" Probing: the two levels. Stalls: "The same." Moves up: seal prevents adding or removing properties but allows changing existing ones; freeze also makes them read-only.
17
2. "Is Object.freeze deep?" Probing: the depth. Stalls: "Yes." Moves up: no — it is shallow, so nested objects stay mutable; a deep freeze means recursing.
18
3. "What happens writing to a frozen property?" Probing: the silent failure. Stalls: "It throws." Moves up: it fails silently in sloppy mode and throws only in strict mode, which is why the bug is easy to miss.
19
4. "How do you update state immutably?" Probing: the pattern. Stalls: "Mutate a copy." Moves up: spread the level being changed and reuse the rest by reference, so unchanged branches keep their identity for comparison.