Object.isSealed()
Determines whether an object is sealed — non-extensible with all properties non-configurable.
Object.isSealed(obj)- Added in JavaScript ES5 (2009)
Parameters
| Parameter | Type | Description |
|---|---|---|
$obj | Object | The object to check. Non-object arguments are treated as already sealed. |
Return value
booleantrue if the given object is sealed, otherwise false.
Changelog
- PHP ES2015Passing a non-object returns true instead of throwing a TypeError, because primitives are immutable by definition.
Object.isSealed() tests a state rather than remembering a call. An object is sealed when it is non-extensible and every one of its own properties is non-configurable. Writability is irrelevant, which is exactly what separates this from Object.isFrozen().
When to reach for it
Use it before code that adds or deletes a property on an object it does not own, so you can branch to building a copy instead of hitting a strict-mode TypeError. It is also handy in tests that assert a factory returned an object with a locked shape.
What trips people up
Every frozen object is also sealed, so isSealed() returning true tells you nothing about whether values are writable — check isFrozen() when that matters.
The empty-object edge case appears here too: Object.isSealed(Object.preventExtensions({})) is true, because with no properties the non-configurable requirement is vacuously satisfied. That also means a non-extensible object can become sealed simply by having its last remaining property deleted. Since ES2015, primitives return true rather than throwing.
Example
When to use it
- Branch to a copy-and-modify path when an object's shape cannot be extended
- Assert in a test that a factory returned a shape-locked object
- Diagnose why adding a property to an object silently did nothing
- Distinguish sealed from merely non-extensible when auditing third-party objects
Frequently asked questions
What is the difference between Object.isSealed() and Object.isFrozen()?
isSealed() only requires the object to be non-extensible with non-configurable properties, while isFrozen() additionally requires every data property to be non-writable — so every frozen object is sealed but not vice versa.
Why does Object.isSealed() return true for an object I only passed to preventExtensions()?
Because it tests state: if the object has no configurable own properties left — which is automatic when it has no properties at all — being non-extensible is enough to qualify as sealed.
Can I unseal an object after Object.isSealed() returns true?
No — integrity levels are irreversible, so the only way back to a mutable shape is to build a new object, for example with object spread.
More examples
Sealed but not frozen
Sealing alone leaves count writable; after freezing, both checks report true, showing that frozen is a strictly stronger state than sealed.
const o = Object.seal({ count: 1 });
console.log(Object.isSealed(o), Object.isFrozen(o));
o.count = 2;
console.log(o.count);
Object.freeze(o);
console.log(Object.isSealed(o), Object.isFrozen(o));Deleting the last property seals an object
Once the only configurable property is gone there is nothing left to violate the rule, so the object flips to both sealed and frozen without either function being called.
const o = Object.preventExtensions({ a: 1 });
console.log("before delete:", Object.isSealed(o), Object.isFrozen(o));
delete o.a; // preventExtensions still allows deletion
console.log("after delete: ", Object.isSealed(o), Object.isFrozen(o));A shape-safe patcher
The sealed input yields a new two-field object while the original keeps only a; the open input is mutated in place and returned by reference.
function addField(target, key, value) {
if (Object.isSealed(target)) {
return { ...target, [key]: value };
}
target[key] = value;
return target;
}
const locked = Object.seal({ a: 1 });
const open = { a: 1 };
console.log(addField(locked, "b", 2), locked);
console.log(addField(open, "b", 2) === open);
Discussion