Кратко
Каждое свойство объекта имеет дескриптор: value (значение), writable (можно ли менять), enumerable (видно ли в циклах), configurable (можно ли удалить/изменить). Object.defineProperty() задаёт свойство с нужными дескрипторами.
Подробно
Object.getOwnPropertyDescriptor: const obj = { name: 'Анна' }; console.log(Object.getOwnPropertyDescriptor(obj, 'name')); // { value: 'Анна', writable: true, enumerable: true, configurable: true }
Object.defineProperty: const user = {}; Object.defineProperty(user, 'name', { value: 'Анна', writable: false, // нельзя изменить enumerable: true, // видно в for...in configurable: false // нельзя удалить });
user.name = 'Борис'; // TypeError (в strict mode) // неявное присваивание игнорируется
Getter/Setter:
let temperature = 20;
const weather = {
get celsius() { return temperature; },
set celsius(value) {
temperature = value;
console.log(Updated: ${value}°C);
}
};
weather.celsius = 25; // 'Updated: 25°C' console.log(weather.celsius); // 25
Определяем все свойства сразу: Object.defineProperties(user, { name: { value: 'Анна', writable: true }, age: { value: 25, writable: false } });
Ментальная модель
Дескриптор — как характеристика товара на этикетке. value — цена. writable — можно ли менять цену. enumerable — виден ли товар в витрине. configurable — можно ли снять товар с продажи.
Примеры
**Самый простой:**
const obj = {};
Object.defineProperty(obj, 'secret', {
value: 42,
writable: false,
enumerable: false,
configurable: false
});
console.log(obj.secret); // 42
obj.secret = 100; // не работает (не в strict mode)
console.log(Object.keys(obj)); // [] — secret не enumerableСкрытое неизменяемое свойство.
**Простой:**
// Getter/Setter
class Temperature {
#celsius = 0;
get fahrenheit() {
return this.#celsius * 9/5 + 32;
}
set fahrenheit(f) {
this.#celsius = (f - 32) * 5/9;
}
get celsius() {
return this.#celsius;
}
set celsius(c) {
this.#celsius = c;
}
}
const temp = new Temperature();
temp.celsius = 100;
console.log(temp.fahrenheit); // 212Getter/Setter для конвертации температуры.
**Реальный пример:**
// Реактивное свойство
function reactiveProperty(obj, key, initialValue) {
let value = initialValue;
Object.defineProperty(obj, key, {
get() {
console.log(`GET ${key}`);
return value;
},
set(newValue) {
console.log(`SET ${key} = ${newValue}`);
value = newValue;
},
enumerable: true,
configurable: true
});
}
const state = {};
reactiveProperty(state, 'count', 0);
state.count; // GET count
state.count = 5; // SET count = 5Реактивные свойства через defineProperty.
Частые ошибки
**Неправильно:** Путать writable и configurable
**Почему:** writable — можно ли менять значение. configurable — можно ли удалить/изменить дескриптор.
**Правильно:** writable = значение защищено. configurable = сама роль защищена.
**Неправильно:** Думать, что configurable: false нельзя изменить
**Почему:** configurable: false запрещает удаление и изменение дескриптора, но writable: true позволяет менять значение.
**Правильно:** configurable: false ≠ readonly. Значение можно менять если writable: true.
Важно запомнить
- writable — можно ли менять значение
- enumerable — видно ли в циклах и Object.keys
- configurable — можно ли удалить/изменить дескриптор
- get/set — вместо value для вычисляемых свойств
- Object.defineProperty для точного контроля
Связь
Назад: Вы знаете объекты (J11). Дескрипторы дают низкоуровневый контроль над свойствами.
Вперёд: Следующий урок (JV16) — каррирование — преобразование функций для частичного применения.