Integrity Levels (preventExtensions, seal, freeze)

Three levels of object mutability restriction, each blocking a specific, increasing set of operations — freeze is shallow.

                Object.preventExtensions(obj) / Object.seal(obj) / Object.freeze(obj)
              

Purpose

JavaScript provides three increasingly strict integrity levels, each locking down a specific, growing set of operations on an object.

The three levels

const obj = { count: 1 };

Object.preventExtensions(obj); // blocks adding new properties only
Object.seal(obj); // + blocks deleting/reconfiguring existing properties
Object.freeze(obj); // + blocks reassigning existing writable properties too
Operation preventExtensions seal freeze
Add a new property Blocked Blocked Blocked
Delete an existing property Allowed Blocked Blocked
Reconfigure a descriptor Allowed Blocked Blocked
Reassign an existing writable value Allowed Allowed Blocked

Behavior notes

  • All three are shallow — locking an object’s own properties has no effect on a nested object referenced by one of them, which remains fully mutable unless separately locked.
  • Object.isExtensible/isSealed/isFrozen check the corresponding state.
  • In strict mode, a blocked operation throws a TypeError; outside strict mode, it’s silently ignored — a common source of a “why didn’t my mutation stick” bug in non-strict code.
  • Object.freeze on a primitive value (a number, a string) is a no-op that returns the value unchanged — primitives are already immutable.

Common mistakes

  • Assuming Object.freeze deep-freezes nested structures — a manual recursive freeze is needed for that.
  • Freezing an object non-strict and being confused when a mutation attempt neither throws nor visibly fails — it silently does nothing.

Runtime notes

Core ECMAScript, identical behavior across every current browser and Node version.

Taught in these lessons

Updated 2026-09-03