Object.seal() у JavaScript
Object.seal() це вбудований метод JavaScript, який «запечатує» об'єкт: він забороняє додавати або видаляти властивості, але дозволяє змінювати значення наявних. Він схожий на Object.freeze(), тільки м’якший, бо не чіпає можливість запису.
Теорія
TL;DR
Object.seal(obj)забороняє додавати і видаляти властивості.- Значення наявних властивостей змінювати можна.
- Технічно це
preventExtensions()плюсconfigurable: falseна кожній власній властивості. writableлишається як було, тому запис працює.- Перевірка стану:
Object.isSealed(obj). - Дія поверхнева: вкладені об'єкти лишаються незапечатаними.
Швидкий приклад
const user = {
name: 'Alice',
age: 25
};
Object.seal(user);
user.age = 30; // можна змінити значення
user.city = 'Kyiv'; // не можна додати нове
delete user.name; // не можна видалити
console.log(user); // { name: 'Alice', age: 30 }Після Object.seal():
- не можна додавати нові властивості;
- не можна видаляти наявні;
- але можна міняти значення вже наявних властивостей.
Синтаксис і перевірка стану
Object.seal(obj)| Аргумент | Опис |
|---|---|
obj | Об'єкт, який потрібно «запечатати» |
Метод повертає той самий об'єкт, але вже з обмеженнями, тобто це не копія.
console.log(Object.isSealed(user)); // trueЩо відбувається «під капотом»
Object.seal(obj) робить три речі:
- Забороняє додавання нових властивостей, тобто виконує
Object.preventExtensions(obj). - Для всіх наявних властивостей виставляє
configurable: false, тож їх не можна видалити і не можна змінити дескриптор. - Залишає
writableбез змін, саме тому значення можна міняти.
Це добре видно на дескрипторі:
const user = { name: 'Alice' };
Object.seal(user);
console.log(Object.getOwnPropertyDescriptor(user, 'name'));Виведе:
{
value: 'Alice',
writable: true,
enumerable: true,
configurable: false
}Видно, що configurable: false, а writable лишилося true.
Порівняння з freeze і preventExtensions
| Метод | Можна міняти значення | Можна додавати | Можна видаляти | Можна міняти дескриптори |
|---|---|---|---|---|
Object.preventExtensions() | Так | Ні | Так | Так |
Object.seal() | Так | Ні | Ні | Ні |
Object.freeze() | Ні | Ні | Ні | Ні |
Тобто seal() це проміжний варіант між «гнучким» і «жорстким». Зверніть увагу на зв'язок: кожен запечатаний об'єкт автоматично нерозширюваний, а кожен заморожений об'єкт автоматично запечатаний, тому Object.isSealed() повертає true і для замороженого об'єкта.
Поверхнева дія (shallow seal)
Object.seal() не захищає вкладені об'єкти:
const user = {
name: 'Alice',
address: { city: 'Kyiv' }
};
Object.seal(user);
user.address.city = 'Lviv'; // можна, вкладений об'єкт не запечатано
user.city = 'Odesa'; // не можна, це нова властивість
console.log(user.address.city); // "Lviv"Щоб «запечатати» все дерево, потрібна глибока запечатка рекурсією:
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;
}Тепер можна «запечатати» все, включно з вкладеними структурами. Перевірка !Object.isSealed(obj[key]) захищає від нескінченної рекурсії на циклічних посиланнях.
Підсумкова таблиця:
| Що робить | Приклад | Поведінка |
|---|---|---|
| «Запечатує» об'єкт | Object.seal(obj) | Забороняє додавання і видалення властивостей |
| Можна змінювати значення | Так | writable лишається true |
| Можна додавати нові властивості | Ні | об'єкт стає нерозширюваним |
| Можна видаляти властивості | Ні | configurable: false |
| Перевірка | Object.isSealed(obj) | |
| Глибина | Поверхнево, тільки верхній рівень |
Типові помилки
- Плутати
seal()ізfreeze().seal()фіксує лише набір ключів; значення після нього спокійно змінюються. - Чекати на помилку при
delete. У нестрогому режиміdelete user.nameпросто повернеfalseі нічого не зробить, а в'use strict'кинеTypeError. - Вважати, що захищено весь граф. Вкладені об'єкти та масиви лишаються повністю змінюваними, потрібен
deepSeal(). - Розраховувати на незмінність стану. Якщо потрібна справжня immutability, це
Object.freeze()або створення нового об'єкта, а неseal(). - Дивуватися, що
Object.isSealed()даєtrueна замороженому об'єкті. Заморожений об'єкт за визначенням також запечатаний, це не баг.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.