Object.freeze()
Freezes an object so its properties cannot be added, removed, reassigned or reconfigured.
Object.freeze(obj)- Added in JavaScript ES5 (2009)
Parameters
| Parameter | Type | Description |
|---|---|---|
$obj | Object | The object to freeze. Non-object arguments are returned unchanged. |
Return value
ObjectThe same object that was passed in — freeze mutates in place and does not return a frozen copy.
Errors
Throws a TypeError when freezing a TypedArray or DataView that has elements; later attempts to modify the frozen object throw a TypeError in strict mode and fail silently otherwise.
Changelog
- PHP ES2015Passing a non-object returns that value unchanged instead of throwing a TypeError, since primitives are already immutable.
Object.freeze() applies the highest integrity level JavaScript offers. On a frozen object you cannot add properties, delete them, reassign their values, change their attributes, or replace the prototype. It returns the same object, so const frozen = Object.freeze(obj) does not leave you an unfrozen original.
When to reach for it
Use it on module-level constants, configuration and lookup tables you export — anything that should read the same on every import. It also makes accidental mutation loud during development, since strict-mode code (which includes all ES modules and class bodies) throws on the write instead of quietly discarding it.
What trips people up
Freezing is shallow. Object.freeze({ opts: {} }) locks the outer object but obj.opts.anything = 1 still works. You need a recursive deep-freeze helper for true immutability.
Failures are silent outside strict mode. In a sloppy-mode script the assignment simply does nothing and returns the value you assigned, so obj.x = 5; console.log(obj.x) printing the old value looks like a bug in the engine. Frozen arrays are affected too: index assignment fails silently and push() throws.
Example
When to use it
- Lock an exported configuration object so importers cannot alter shared state
- Define an enum-like constant map that nothing downstream can extend
- Guard a default-options object that gets merged into but never modified
- Catch accidental mutation early by making writes throw in strict-mode code
Frequently asked questions
Does Object.freeze() work on nested objects?
No — it is shallow, so properties of nested objects remain writable; you need a recursive deepFreeze helper that walks every own key and freezes as it goes.
Why does assigning to a frozen object not throw an error?
Outside strict mode a rejected write fails silently; ES modules, class bodies and any code under "use strict" throw a TypeError instead.
What is the difference between Object.freeze() and Object.seal()?
Both prevent adding and deleting properties, but a sealed object still lets you change existing property values while a frozen one does not.
More examples
Deep freezing
Recursion is required because Object.freeze() only touches one level; now the innermost write is rejected too.
function deepFreeze(object) {
for (const name of Reflect.ownKeys(object)) {
const value = object[name];
if ((value && typeof value === "object") || typeof value === "function") {
deepFreeze(value);
}
}
return Object.freeze(object);
}
const tree = deepFreeze({ a: { b: { c: 1 } } });
try { tree.a.b.c = 2; } catch { console.log("nested write rejected"); }
console.log(tree.a.b.c, Object.isFrozen(tree.a.b));Frozen arrays
Mutating methods fail on a frozen array, while non-mutating ones like concat() still work because they return a new array.
const list = Object.freeze([1, 2, 3]);
try { list[0] = 99; } catch { console.log("index write rejected"); }
try { list.push(4); } catch (e) { console.log("push threw:", e.constructor.name); }
console.log(list, list.length);
console.log(list.concat(4));Freeze returns the same object
There is no unfrozen copy left behind, and since ES2015 a primitive argument is simply returned unchanged instead of throwing.
const original = { a: 1 };
const returned = Object.freeze(original);
console.log(returned === original);
console.log(Object.isFrozen(original));
console.log(Object.freeze(42));
Discussion