Object.freeze, Object.seal & Immutability0%

Object.freeze, Object.seal & Immutability

Beginner12 min read•Updated: Jul 11, 2026
Study Materials

Object.freeze, Object.seal & Immutability in Modern JavaScript

In state management systems (Redux, Zustand) and security configurations, accidental object mutation causes hard-to-track bugs. Modern JavaScript provides varying levels of object locking: Object.preventExtensions(), Object.seal(), and Object.freeze().


1. The Immutability Spectrum

Output
┌────────────────────────────────────────────────────────┐
│ Level 1: Object.preventExtensions(obj) │
│ • CANNOT add new properties │
│ • CAN modify existing properties │
│ • CAN delete existing properties │
├────────────────────────────────────────────────────────┤
│ Level 2: Object.seal(obj) │
│ • CANNOT add new properties │
│ • CANNOT delete existing properties │
│ • CAN modify existing property values │
├────────────────────────────────────────────────────────┤
│ Level 3: Object.freeze(obj) │
│ • CANNOT add new properties │
│ • CANNOT delete existing properties │
│ • CANNOT modify existing property values (Read-Only) │
└────────────────────────────────────────────────────────┘

2. Property Descriptors Explained

Under the hood, these methods configure internal Property Descriptors:

JavaScript
const user = { name: 'Sarah' };
 
// Inspect property descriptor
console.log(Object.getOwnPropertyDescriptor(user, 'name'));
// { value: 'Sarah', writable: true, enumerable: true, configurable: true }
  • writable: If false, value cannot be reassigned.
  • configurable: If false, property cannot be deleted and descriptors cannot be modified.
  • enumerable: If false, hidden from for...in and Object.keys().
JavaScript
// Object.freeze() sets:
// 1. Object extensible = false
// 2. All own properties: writable = false, configurable = false

3. Strict Mode Enforcement

In non-strict mode, attempting to mutate a frozen object fails silently. In strict mode ('use strict'), it throws a TypeError:

JavaScript
'use strict';
 
const appConfig = Object.freeze({
apiEndpoint: 'https://api.example.com',
timeout: 5000
});
 
// appConfig.timeout = 10000;
// TypeError: Cannot assign to read only property 'timeout' of object '#<Object>'

4. The Critical Gotcha: Object.freeze is SHALLOW!

Object.freeze() only freezes top-level properties. Nested objects remain mutable references!

JavaScript
const enterpriseSettings = Object.freeze({
appName: 'MasterPortal',
database: {
host: 'localhost', // NESTED OBJECT!
port: 5432
}
});
 
// DANGER: Nested mutation succeeds!
enterpriseSettings.database.port = 3306;
console.log(enterpriseSettings.database.port); // 3306!

The Solution: Recursive Deep Freeze Utility

JavaScript
function deepFreeze(obj) {
// Retrieve all own property names
const propNames = Object.getOwnPropertyNames(obj);
 
// Freeze properties before freezing self
for (const name of propNames) {
const value = obj[name];
if (value && typeof value === 'object') {
deepFreeze(value); // Recursive call
}
}
 
return Object.freeze(obj);
}
 
const safeSettings = deepFreeze({
database: { port: 5432 }
});
 
// safeSettings.database.port = 3306; // TypeError: Cannot assign to read only property!

Interactive Quiz

Practice Quiz

Question 1
What is the primary difference between Object.seal() and Object.freeze()?
Question 2
What happens when code attempts to mutate a frozen object in strict mode ('use strict')?
Question 3
Does calling Object.freeze(obj) prevent modifications to nested objects (e.g. obj.nested.key = val)?
Question 4
Which method checks whether an object has been sealed?
Question 5
What property descriptor controls whether a property can be deleted with the delete operator?
Next Lesson

Symbols & Well-Known Symbols

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext