Object.preventExtensions() у JavaScript
Object.preventExtensions() це вбудований метод JavaScript, який забороняє додавати до об'єкта нові властивості, але дозволяє змінювати і видаляти вже наявні. Це найм'якша форма захисту об'єкта, на відміну від seal() і freeze().
Теорія
TL;DR
Object.preventExtensions(obj)забороняє додавати нові властивості.- Наявні властивості можна змінювати і можна видаляти.
- Дескриптори
configurable,writable,enumerableлишаються без змін. - Перевірка стану:
Object.isExtensible(obj)повернеfalse. - Заборона поширюється і на
Object.defineProperty(), який кинеTypeError. - Успадковані через прототип властивості лишаються доступними.
Швидкий приклад
const user = {
name: 'Alice',
age: 25
};
Object.preventExtensions(user);
user.city = 'Kyiv'; // не додасться
delete user.age; // можна видалити
user.name = 'Oleh'; // можна змінити
console.log(user); // { name: 'Oleh' }Після Object.preventExtensions():
- не можна додати нові властивості;
- можна видалити старі;
- можна міняти наявні значення.
Синтаксис і перевірка стану
Object.preventExtensions(obj)| Аргумент | Опис |
|---|---|
obj | Об'єкт, до якого не можна буде додати нові властивості |
Повертає сам об'єкт, уже нерозширюваний, тобто це не копія.
console.log(Object.isExtensible(user)); // falseObject.isExtensible(obj) повертає false, якщо до об'єкта не можна додавати нові властивості. Операція незворотна: зробити об'єкт розширюваним назад неможливо.
Що відбувається «під капотом»
Object.preventExtensions(obj) робить таке:
- забороняє додавання нових властивостей, зокрема й через
Object.defineProperty(); - наявні властивості лишаються змінюваними та видаляними;
configurable,writable,enumerableне чіпаються.
Спроба додати властивість через defineProperty не мовчить, а кидає помилку:
const obj = {};
Object.preventExtensions(obj);
try {
Object.defineProperty(obj, 'x', { value: 1 });
} catch (err) {
console.log('Помилка:', err.message);
}Виведе:
Помилка: Cannot define property x, object is not extensibleЗвичайне присвоєння obj.x = 1 поводиться інакше: у нестрогому режимі воно мовчки нічого не робить, а в 'use strict' теж кидає TypeError.
Відмінності від seal() і freeze()
| Метод | Можна додавати | Можна видаляти | Можна змінювати | Дескриптори configurable |
|---|---|---|---|---|
preventExtensions() | Ні | Так | Так | Без змін |
seal() | Ні | Ні | Так | Усі configurable: false |
freeze() | Ні | Ні | Ні | Усі configurable: false, writable: false |
Тобто preventExtensions() це найм'якший варіант захисту. Він просто «закриває вхід», але не заважає працювати з тим, що вже є.
Прототипи і успадковані властивості
const parent = { role: 'user' };
const child = Object.create(parent);
Object.preventExtensions(child);
child.name = 'Alice'; // не додасться
console.log(child.name); // undefined
console.log(child.role); // "user", успадковано з прототипуpreventExtensions() не впливає на успадковані властивості, вони лишаються доступними через прототип. Обмежується лише набір власних властивостей конкретного об'єкта; сам прототип, якщо його не захистити окремо, спокійно можна розширювати, і нові поля одразу стануть видимими для child.
Підсумкова таблиця:
| Поведінка | Дозволено? |
|---|---|
| Додавати нові властивості | Ні |
| Видаляти наявні | Так |
| Змінювати значення | Так |
| Міняти дескриптори | Так |
| Перевірка | Object.isExtensible(obj) |
Типові помилки
- Очікувати, що об'єкт стане незмінним.
preventExtensions()не боронить ні запис, ніdelete; для цього потрібніseal()абоfreeze(). - Чекати виключення від звичайного присвоєння.
obj.x = 1у нестрогому режимі мовчки провалюється, помилку ви побачите лише під'use strict'або відObject.defineProperty(). - Сподіватися відкотити захист. Зробити об'єкт розширюваним назад не можна, стан незворотний.
- Забувати про прототип. Захищено лише власні властивості; додавання полів у прототип і далі впливає на об'єкт.
- Вважати дію глибокою. Вкладені об'єкти лишаються повністю розширюваними, їх треба обробляти окремо.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.