Object.defineProperty() создаёт новое свойство объекта или перенастраивает существующее.
Главная идея метода в том, что он позволяет не просто записать значение, а точно управлять настройками свойства.
Синтаксис
Object.defineProperty(obj, propertyName, descriptor)
obj - объект, в который нужно добавить или изменить свойство.
propertyName - имя свойства.
descriptor - объект с настройками свойства.
Что делает Object.defineProperty()
Метод создаёт свойство или меняет его дескриптор.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
});
console.log(user.name); // "Anna"
Что возвращает метод
Object.defineProperty() возвращает тот же самый объект.
const user = {};
const result = Object.defineProperty(user, "name", {
value: "Anna",
});
console.log(result === user); // true
Это важно: метод не создаёт новый объект, а работает с существующим.
Обычное свойство через value
Самый простой вариант - создать свойство через value.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
});
console.log(user.name); // "Anna"
Но здесь есть важный нюанс: по умолчанию некоторые настройки будут false.
writable, enumerable, configurable
Для обычного свойства дескриптор может содержать:
value- значение свойстваwritable- можно ли менять значениеenumerable- видно ли свойство в перечисленииconfigurable- можно ли удалять или перенастраивать свойство
Пример:
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
writable: true,
enumerable: true,
configurable: true,
});
По умолчанию флаги равны false
Это один из самых важных моментов.
Если не указать writable, enumerable и configurable, они будут false.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
});
user.name = "Ivan";
console.log(user.name); // "Anna"
console.log(Object.keys(user)); // []
Здесь свойство:
- не меняется
- не попадает в
Object.keys() - не настраивается свободно как обычное
writable: можно ли менять значение
Если writable: false, значение свойства нельзя изменить.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
writable: false,
});
user.name = "Ivan";
console.log(user.name); // "Anna"
Если writable: true, значение можно менять.
enumerable: видно ли свойство при перечислении
Если enumerable: false, свойство не будет видно в Object.keys() и похожих способах перебора.
const user = {};
Object.defineProperty(user, "secret", {
value: "123",
enumerable: false,
});
console.log(Object.keys(user)); // []
console.log(user.secret); // "123"
Свойство есть, но в перечислении его не видно.
configurable: можно ли перенастраивать свойство
Если configurable: false, свойство нельзя удалить и сложно перенастроить.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
configurable: false,
});
delete user.name;
console.log(user.name); // "Anna"
Это полезно, когда нужно жёстко закрепить поведение свойства.
Getter и setter
Через Object.defineProperty() можно создавать не только обычные свойства, но и accessor properties.
const user = {
firstName: "Anna",
lastName: "Smith",
};
Object.defineProperty(user, "fullName", {
get() {
return `${this.firstName} ${this.lastName}`;
},
});
console.log(user.fullName); // "Anna Smith"
Здесь fullName не хранит значение напрямую, а вычисляется через getter.
Setter
Через setter можно управлять записью в свойство.
const user = {
firstName: "Anna",
lastName: "Smith",
};
Object.defineProperty(user, "fullName", {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(value) {
const [first, last] = value.split(" ");
this.firstName = first;
this.lastName = last;
},
});
user.fullName = "Ivan Petrov";
console.log(user.firstName); // "Ivan"
console.log(user.lastName); // "Petrov"
Нельзя смешивать value/writable и get/set
Это важное правило.
В одном дескрипторе нельзя одновременно использовать:
valueилиwritable- и
getилиset
Такой код приведёт к ошибке:
Object.defineProperty(obj, "x", {
value: 1,
get() {
return 2;
},
});
Нужно выбрать либо обычное свойство, либо accessor property.
Object.defineProperty() и обычное присваивание
Обычная запись:
user.name = "Anna";
создаёт обычное свойство с привычными настройками.
А Object.defineProperty() нужен, когда нужно точнее управлять свойством.
Object.defineProperty(user, "name", {
value: "Anna",
writable: false,
enumerable: false,
});
То есть это инструмент для более тонкой настройки.
Проверка через Object.getOwnPropertyDescriptor()
Очень удобно смотреть результат через дескриптор.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
enumerable: false,
});
console.log(Object.getOwnPropertyDescriptor(user, "name"));
Так можно сразу увидеть, какие флаги реально установились.
Object.defineProperty() не меняет прототип
Метод работает только со свойством самого объекта.
Он не связан с прототипной цепочкой напрямую.
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
});
console.log(user.name); // "Anna"
Это просто настройка свойства конкретного объекта.
Массивы тоже работают
Массив - это тоже объект, поэтому метод работает и с ним.
const arr = ["a", "b"];
Object.defineProperty(arr, "0", {
value: "x",
});
console.log(arr); // ["x", "b"]
Но с массивами таким способом обычно работают осторожно, чтобы не получить странное поведение.
Когда это полезно
Object.defineProperty() удобно использовать, когда:
- нужно скрыть свойство из перечисления
- нужно запретить изменение значения
- нужно создать getter/setter
- нужно точно настроить поведение свойства
Пример:
const config = {};
Object.defineProperty(config, "version", {
value: 1,
writable: false,
enumerable: true,
configurable: false,
});
Частые ошибки
Забывать, что writable/enumerable/configurable по умолчанию false
const user = {};
Object.defineProperty(user, "name", {
value: "Anna",
});
console.log(Object.keys(user)); // []
Это поведение часто удивляет.
Пытаться смешать value и get/set
Object.defineProperty(obj, "x", {
value: 1,
get() {
return 2;
},
});
Такой дескриптор недопустим.
Думать, что метод создаёт новый объект
const user = {};
const result = Object.defineProperty(user, "name", {
value: "Anna",
});
console.log(result === user); // true
Метод изменяет существующий объект.
Быстрая памятка
Object.defineProperty()создаёт или перенастраивает свойство объекта- метод возвращает тот же самый объект
- через дескриптор можно управлять
value,writable,enumerable,configurable - через
getиsetможно создавать accessor properties - по умолчанию многие флаги будут
false
Коротко
Object.defineProperty() - это способ точно настроить свойство объекта в JavaScript. Главное, что стоит запомнить: этот метод нужен не для обычного присваивания, а для управления дескриптором свойства, его видимостью, изменяемостью и поведением через getter/setter.