Skip to main content

Object.seal() in JavaScript

Object.seal() is a built-in JavaScript method that "seals" an object: it forbids adding or deleting properties but allows changing the values of the existing ones. It is similar to Object.freeze(), only softer, because it does not touch writability.

Theory

TL;DR

  • Object.seal(obj) forbids adding and deleting properties.
  • The values of existing properties can be changed.
  • Technically it is preventExtensions() plus configurable: false on every own property.
  • writable stays as it was, so writing works.
  • To check the state: Object.isSealed(obj).
  • The effect is shallow: nested objects stay unsealed.

Quick example

javascript
const user = { name: 'Alice', age: 25 }; Object.seal(user); user.age = 30; // the value can be changed user.city = 'Kyiv'; // a new one cannot be added delete user.name; // it cannot be deleted console.log(user); // { name: 'Alice', age: 30 }

After Object.seal():

  • new properties cannot be added;
  • existing ones cannot be deleted;
  • but the values of existing properties can be changed.

Syntax and checking the state

javascript
Object.seal(obj)
ArgumentDescription
objThe object to "seal"

The method returns the same object, now with the restrictions applied, so it is not a copy.

javascript
console.log(Object.isSealed(user)); // true

What happens under the hood

Object.seal(obj) does three things:

  1. Forbids adding new properties, that is, it performs Object.preventExtensions(obj).
  2. Sets configurable: false on every existing property, so they cannot be deleted and their descriptors cannot be changed.
  3. Leaves writable untouched, which is exactly why values can still be changed.

This is easy to see on the descriptor:

javascript
const user = { name: 'Alice' }; Object.seal(user); console.log(Object.getOwnPropertyDescriptor(user, 'name'));

It prints:

javascript
{ value: 'Alice', writable: true, enumerable: true, configurable: false }

You can see that configurable: false while writable stayed true.

Comparison with freeze and preventExtensions

MethodCan change valuesCan addCan deleteCan change descriptors
Object.preventExtensions()YesNoYesYes
Object.seal()YesNoNoNo
Object.freeze()NoNoNoNo

So seal() is the middle ground between "flexible" and "strict". Note the relationship: every sealed object is automatically non-extensible, and every frozen object is automatically sealed, which is why Object.isSealed() also returns true for a frozen object.

Shallow seal

Object.seal() does not protect nested objects:

javascript
const user = { name: 'Alice', address: { city: 'Kyiv' } }; Object.seal(user); user.address.city = 'Lviv'; // allowed, the nested object is not sealed user.city = 'Odesa'; // not allowed, that is a new property console.log(user.address.city); // "Lviv"

To "seal" the whole tree you need a deep seal with recursion:

javascript
function deepSeal(obj) { Object.seal(obj); for (const key in obj) { if (typeof obj[key] === 'object' && obj[key] !== null && !Object.isSealed(obj[key])) { deepSeal(obj[key]); } } return obj; }

Now everything can be "sealed", including nested structures. The !Object.isSealed(obj[key]) check protects against infinite recursion on circular references.

Summary table:

What it doesExampleBehaviour
"Seals" the objectObject.seal(obj)Forbids adding and deleting properties
Values can be changedYeswritable stays true
New properties can be addedNothe object becomes non-extensible
Properties can be deletedNoconfigurable: false
CheckObject.isSealed(obj)
DepthShallow, top level only

Common mistakes

  • Confusing seal() with freeze(). seal() only fixes the set of keys; values can still be changed afterwards.
  • Expecting an error on delete. In sloppy mode delete user.name simply returns false and does nothing, while under 'use strict' it throws a TypeError.
  • Assuming the whole graph is protected. Nested objects and arrays stay fully mutable, you need deepSeal().
  • Counting on immutable state. If you need real immutability, that is Object.freeze() or building a new object, not seal().
  • Being surprised that Object.isSealed() returns true for a frozen object. A frozen object is sealed by definition, that is not a bug.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.