Property Descriptors
Property Descriptor — объект метаданных, описывающий поведение свойства объекта: можно ли его перезаписать (
writable), перечислить (enumerable) и удалить или переконфигурировать (configurable).
Зачем нужно
Дескрипторы дают точный контроль над поведением свойств объектов: создание констант, скрытых свойств, вычисляемых геттеров/сеттеров. Понимание дескрипторов необходимо для реализации реактивности (Vue 2 Object.defineProperty), создания иммутабельных структур и построения надёжных библиотечных API.
Где используется
- Создание неизменяемых свойств (константы в объекте)
- Геттеры/сеттеры для вычисляемых свойств
- Скрытие служебных свойств от
for...inиObject.keys() - Реализация реактивности (Vue 2, MobX)
- Защита объектов через
Object.freeze/Object.seal
Основной контент
Чтение дескриптора
const obj = { x: 42 };
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
// {
// value: 42,
// writable: true,
// enumerable: true,
// configurable: true
// }
Object.defineProperty
const config = {};
Object.defineProperty(config, 'MAX_SIZE', {
value: 100,
writable: false, // нельзя перезаписать
enumerable: true, // виден в for...in
configurable: false // нельзя удалить/переконфигурировать
});
config.MAX_SIZE = 200; // тихо игнорируется (или TypeError в strict mode)
console.log(config.MAX_SIZE); // 100
delete config.MAX_SIZE; // тихо игнорируется
console.log(config.MAX_SIZE); // 100
// Скрытое свойство (enumerable: false)
Object.defineProperty(config, '_internal', {
value: 'secret',
enumerable: false,
writable: true,
configurable: true
});
console.log(Object.keys(config)); // ['MAX_SIZE'] — _internal скрыто
console.log(config._internal); // 'secret' — но доступно напрямую
Геттеры и сеттеры
const person = {
_firstName: 'Иван',
_lastName: 'Иванов'
};
Object.defineProperty(person, 'fullName', {
get {
return `${this._firstName} ${this._lastName}`;
},
set(value) {
const [first, ...rest] = value.split(' ');
this._firstName = first;
this._lastName = rest.join(' ');
},
enumerable: true,
configurable: true
});
console.log(person.fullName); // 'Иван Иванов'
person.fullName = 'Пётр Петров';
console.log(person._firstName); // 'Пётр'
// Геттер в литерале объекта (синтаксический сахар)
const circle = {
radius: 5,
get area { return Math.PI * this.radius ** 2; }
};
console.log(circle.area.toFixed(2)); // '78.54'
Object.defineProperties и заморозка
// Несколько свойств за раз
const point = {};
Object.defineProperties(point, {
x: { value: 0, writable: true, enumerable: true, configurable: true },
y: { value: 0, writable: true, enumerable: true, configurable: true }
});
// Object.freeze = все writable: false, configurable: false (поверхностно)
const COLORS = Object.freeze({ RED: '#ff0000', GREEN: '#00ff00' });
COLORS.RED = '#000'; // тихо игнорируется
console.log(COLORS.RED); // '#ff0000'
Частые ошибки
- Тихое игнорирование в non-strict mode — запись в
writable: falseв обычном режиме просто игнорируется без ошибки. В'use strict'выбрасываетсяTypeError. Это маскирует баги. Object.freeze— только поверхностная заморозка — вложенные объекты не замораживаются. Для глубокой заморозки нужна рекурсивная функция.- Смешение value и get/set — дескриптор не может одновременно содержать
value/writableиget/set. ЭтоTypeError.
Связанные темы
Ресурсы
- MDN — Object.defineProperty
- javascript.info — Флаги и дескрипторы
- doka.guide — Object.defineProperty
⚡ Источник: Что такое Object в JavaScript согласно спецификации · AsForJS
- 📅 2025-02-03 · YouTube
- Тезисы: Property Descriptor — это конкретная Specification Type. У всякого свойства внутри объекта есть либо Data Descriptor (
value,writable), либо Accessor Descriptor (get,set). Любое присваиваниеobj.x = 5под капотом — это[[DefineOwnProperty]]с дескриптором