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