Коротка відповідь
juniorДескриптори властивостей – це внутрішні об’єкти, що описують атрибути (value, writable, enumerable, configurable) і гетери/сетери. Вони дозволяють контролювати доступ до властивостей, створювати гнучкі API та захищати дані. Практика: використання Object.defineProperty для створення read‑only полів, гетерів чи перехоплення присвоєнь.
Повне пояснення
Що це і навіщо Дескриптори властивостей – внутрішні структури, що зберігають метадані про кожну властивість об’єкта. Вони визначають, чи можна змінювати значення (writable), чи буде властивість перераховувана в циклі for…in (enumerable) і чи можна видалити її (configurable). Також дескриптори підтримують гетери/сетери, що дозволяє виконувати логіку під час доступу.
Ключові принципи/терміни
value– фактичне значення.writable,enumerable,configurable– булеві прапорці.get,set– функції‑гетери/сетери.Object.getOwnPropertyDescriptor(obj, prop)– отримати дескриптор.Object.defineProperty(obj, prop, descriptor)– створити/змінити дескриптор.
Як це працює
При доступі до властивості JavaScript‑рушій перевіряє дескриптор. Якщо присутній get, викликається функція; якщо set – передається нове значення. Якщо властивість не writable, присвоєння просто ігнорується (в strict mode – помилка).
Практика та реалізація
const user = {};
Object.defineProperty(user, 'id', {
value: 123,
writable: false,
enumerable: true,
configurable: false
});
user.id = 456; // нічого не зміниться
interface Person {
readonly name: string;
}
const p: Person = { name: 'Alice' };
// p.name = 'Bob'; // TS помилка
Тестування
import { describe, it, expect } from 'vitest';
describe('descriptors', () => {
it('should be read‑only', () => {
const obj = {};
Object.defineProperty(obj, 'x', { value: 1, writable: false });
expect(() => { obj.x = 2; }).not.toThrow(); // в JS нічого не зміниться
expect(obj.x).toBe(1);
});
});
Особливості в контексті JS Core
- Дескриптори використовуються у
Object.freeze,Object.sealіObject.preventExtensions. - Підтримка гетерів/сетери дозволяє реалізовувати реактивність (наприклад, Vue 2).
- У TypeScript
readonlyіconstкомпілюються до відповідних дескрипторів.
Оптимізація, типові помилки та edge cases
- Забуваємо встановити
configurable: true→ неможливо змінити дескриптор пізніше. - Використовуємо
Object.definePropertyбезenumerable: false, що розкриває внутрішні поля. - Під час
Object.assignдескриптори не копіюються – треба використовуватиObject.getOwnPropertyDescriptors. - У strict mode присвоєння read‑only властивості кидає помилку, що треба враховувати.
- При створенні гетерів/сетери слід уникати рекурсивних викликів.
- Не можна змінювати
writableз true на false безconfigurable: true. - Під час видалення властивості (
delete obj.prop) треба матиconfigurable: true. - При використанні
Object.definePropertiesз масивом дескрипторів треба перевіряти, що ключі не дублюються.
Cheatsheet + follow‑up питання
Object.getOwnPropertyDescriptor(obj, prop)→ отримати дескриптор.Object.defineProperty(obj, prop, { get() {}, set(value) {} })→ гетер/сет.Object.freeze(obj)→ усі властивості стають read‑only, non‑configurable.
Follow‑up: Як працює Object.seal і чим він відрізняється від Object.freeze?