Suggest an editImprove this articleRefine the answer for “Object.seal() in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`Object.seal()` "seals" an object: you cannot add new properties or delete existing ones, but you are allowed to change the values of the properties that are already there.** Under the hood it calls `Object.preventExtensions()` and sets `configurable: false` on every own property while leaving `writable: true`. Check the state with `Object.isSealed(obj)`; the effect is shallow, so nested objects stay unsealed. ```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 } ``` **Key point:** `seal()` fixes the set of keys, not the values; it is the middle ground between `preventExtensions()` and `freeze()`.Shown above the full answer for quick recall.Answer (EN)Image**`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) ``` | Argument | Description | | --- | --- | | `obj` | The 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 | Method | Can change values | Can add | Can delete | Can change descriptors | | --- | --- | --- | --- | --- | | `Object.preventExtensions()` | Yes | No | Yes | Yes | | `Object.seal()` | Yes | No | No | No | | `Object.freeze()` | No | No | No | No | 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 does | Example | Behaviour | | --- | --- | --- | | "Seals" the object | `Object.seal(obj)` | Forbids adding and deleting properties | | Values can be changed | Yes | `writable` stays `true` | | New properties can be added | No | the object becomes non-extensible | | Properties can be deleted | No | `configurable: false` | | Check | `Object.isSealed(obj)` | | | Depth | Shallow, 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.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.