Прапорці writable, enumerable, configurable
Прапорці writable, enumerable і configurable це три службові параметри в дескрипторі властивості (property descriptor), які керують поведінкою властивостей об'єктів у JavaScript. Під час звичайної роботи з об'єктом вони непомітні, але саме вони визначають, чи можна властивість змінити, видалити або перерахувати.
Теорія
TL;DR
| Прапорець | Що робить | За замовчуванням |
|---|---|---|
writable | Дозволяє змінювати значення властивості | false (якщо властивість створено через defineProperty) |
enumerable | Робить властивість видимою під час перебору (for...in, Object.keys) | false |
configurable | Дозволяє видаляти властивість і змінювати її прапорці | false |
- Звичайне присвоєння
obj.key = valueстворює властивість з усіма прапорцямиtrue. - Прочитати прапорці можна через
Object.getOwnPropertyDescriptor(obj, key). - Задати їх можна лише через
Object.defineProperty(obj, key, descriptor).
Швидкий приклад
javascript
const user = {};
Object.defineProperty(user, 'name', {
value: 'Alice',
writable: false, // не можна змінювати
enumerable: false, // не з'являється в циклах
configurable: false // не можна видалити або змінити прапорці
});
console.log(user.name); // "Alice"
user.name = 'Bob'; // не змінюється
delete user.name; // не видаляється
console.log(Object.keys(user)); // [] бо властивість не перераховуєтьсяwritable: чи можна змінювати значення
javascript
const user = {};
Object.defineProperty(user, 'age', {
value: 25,
writable: false
});
user.age = 30; // не спрацює
console.log(user.age); // 25writable: trueдозволяє змінювати значення;writable: falseробить властивість лише для читання.
У нестрогому режимі запис у таку властивість просто мовчки ігнорується, у strict mode кидається TypeError.
enumerable: чи показувати властивість під час перебору
javascript
const user = {};
Object.defineProperty(user, 'secret', {
value: '12345',
enumerable: false
});
console.log(user.secret); // доступно напряму
console.log(Object.keys(user)); // [] бо властивість не видно
for (const key in user) console.log(key); // нічого не виведеenumerable: trueробить властивість видимою уfor...in,Object.keys(),JSON.stringify();enumerable: falseробить її «прихованою».
Приклад з реального життя: вбудовані методи (toString, valueOf) мають enumerable: false, щоб не заважати під час перебору.
configurable: чи можна видалити або змінити прапорці
javascript
const user = {};
Object.defineProperty(user, 'id', {
value: 10,
configurable: false
});
delete user.id; // не видалиться
console.log(user.id); // 10
// Спробуємо змінити writable:
Object.defineProperty(user, 'id', { writable: true });
// TypeError: Cannot redefine property: idconfigurable: trueдозволяє видалити властивість або змінити її прапорці;configurable: falseзабороняє видалення і змінуenumerable,configurableта перехідwritableзfalseнаtrue.
Єдине, що ще можна змінити у такої властивості, це
writableзtrueнаfalse, але не навпаки.
Як прочитати і як задати прапорці
Прочитати:
javascript
const obj = { name: 'Alice' };
const descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
console.log(descriptor);Виведе:
javascript
{
value: 'Alice',
writable: true,
enumerable: true,
configurable: true
}Задати:
javascript
Object.defineProperty(obj, 'prop', {
value: 42,
writable: false,
enumerable: true,
configurable: false
});Підсумок:
| Прапорець | Призначення | Приклад |
|---|---|---|
writable | Чи можна змінювати значення властивості | user.age = 30 |
enumerable | Чи видно властивість під час перебору | Object.keys(user) |
configurable | Чи можна видалити або перевизначити властивість | delete user.prop |
Типові помилки
- Забувати, що
definePropertyставить усі прапорці уfalse. Властивість, створена без явногоenumerable: true, зникає зObject.keys()і з результатуJSON.stringify(). - Чекати на помилку від запису у
writable: false. Без'use strict'присвоєння мовчки не спрацьовує, і баг помічають пізно. - Плутати
writable: falseз незмінністю об'єкта. Якщо у властивості лежить об'єкт, його поля все одно можна змінювати; глибока заморозка це вжеObject.freezeпо всьому дереву. - Розраховувати повернути
configurableуtrue. Це незворотна операція, тому спершу продумують, які властивості справді треба «запечатати». - Вважати, що
enumerable: falseприховує дані. Властивість і далі читається напряму і видима дляObject.getOwnPropertyNames()таReflect.ownKeys(). - Використовувати спред або
Object.assignдля копіювання. Вони переносять лише перераховувані власні властивості і втрачають прапорці; для точної копії потрібніObject.getOwnPropertyDescriptorsіObject.defineProperties.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.