Свойства объектов: литералы, дескрипторы, аксессоры
Основной способ работы со свойствами объектов
Наиболее простой и часто используемый метод - определение свойств непосредственно в литерале объекта и доступ через точку. Пример:
let user = {
name: 'Анна',
age: 25
};
console.log(user.name); // Анна
user.age = 26;
delete user.name;Js object (объекты javascript)
Такой подход подходит для большинства задач, когда свойства известны заранее и их поведение не требует специальной настройки. Однако он не позволяет управлять атрибутами свойства: возможностью перезаписи, удаления, перечисления.
Как задать свойство с именем, полученным из переменной?
Использование квадратных скобок (computed property names) позволяет вычислять имя свойства на лету.
let key = 'email';
let user = {
[key]: 'user@example.com'
};
console.log(user.email); // user@example.comProperty js (свойства объектов в javascript)
Как сделать свойство только для чтения?
Метод Object.defineProperty позволяет задать дескриптор свойства, в том числе writable.
let user = {};
Object.defineProperty(user, 'id', {
value: 123,
writable: false,
configurable: true,
enumerable: true
});
user.id = 456; // игнорируется в строгом режиме TypeError
console.log(user.id); // 123
Как скрыть свойство от перечисления в for...in или Object.keys?
Установка enumerable: false делает свойство невидимым для перебора.
let user = { name: 'Анна' };
Object.defineProperty(user, 'secret', {
value: 'confidential',
enumerable: false
});
for(let key in user) console.log(key); // только "name"
console.log(Object.keys(user)); // ['name']
Как создать свойство, значение которого вычисляется при обращении?
Использование геттера (get) и опционально сеттера (set).
let user = {
firstName: 'Иван',
lastName: 'Петров',
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
set fullName(value) {
[this.firstName, this.lastName] = value.split(' ');
}
};
console.log(user.fullName); // Иван Петров
user.fullName = 'Анна Сидорова';
console.log(user.firstName); // Анна
Как запретить добавление новых свойств в объект?
Методы Object.preventExtensions, Object.seal, Object.freeze постепенно усиливают защиту.
let user = { name: 'Иван' };
Object.preventExtensions(user);
user.age = 30; // игнорируется или TypeError
console.log(user.age); // undefined
Object.seal(user); // дополнительно делает все свойства non-configurable
Object.freeze(user); // ещё и writable: false
Как создать уникальное имя свойства, не конфликтующее с другими?
Тип Symbol позволяет создавать уникальные идентификаторы.
let sym = Symbol('id');
let user = {
[sym]: 123,
name: 'Анна'
};
console.log(user[sym]); // 123
console.log(Object.keys(user)); // ['name'] - Symbol не отображается
Пример 1: Геттер/сеттер с проверкой
В этом примере свойство password использует геттер для маскировки и сеттер для валидации длины.
let user = {
_password: '',
set password(value) {
if (value.length < 6) {
throw new Error('Пароль должен быть не менее 6 символов');
}
this._password = value;
},
get password() {
return this._password ? '***' : 'не установлен';
}
};
user.password = 'секрет123';
console.log(user.password); // ***
console.log(user._password); // 'секрет123'
***
Пример 2: Object.defineProperties для нескольких свойств
Метод позволяет задать дескрипторы сразу для группы свойств с разными характеристиками.
let book = {};
Object.defineProperties(book, {
title: { value: 'JavaScript: The Good Parts', writable: false, enumerable: true },
year: { value: 2008, writable: true, enumerable: false },
getInfo: {
get: function() { return `${this.title} (${this.year})`; },
enumerable: true
}
});
console.log(book.title); // JavaScript: The Good Parts
console.log(Object.keys(book)); // ['title', 'getInfo']
['title', 'getInfo']
Пример 3: Символы для скрытых метаданных
Symbol позволяет создать уникальные ключи, которые не конфликтуют с обычными строковыми свойствами и не участвуют в сериализации.
const secretKey = Symbol('secret');
function createUser(name) {
let user = { name };
user[secretKey] = Math.random();
return user;
}
let u = createUser('Анна');
console.log(Object.getOwnPropertySymbols(u)); // [ Symbol(secret) ]
console.log(JSON.stringify(u)); // {"name":"Анна"}
[ Symbol(secret) ]
{"name":"Анна"}
Пример 4: Динамические имена свойств с Object.fromEntries
Удобный способ создания объекта из массива пар ключ-значение, особенно при обработке данных.
let entries = [['a', 1], ['b', 2]];
let obj = Object.fromEntries(entries);
console.log(obj); // { a: 1, b: 2 }
let keyValuePairs = ['x', 'y', 'z'].map(k => [k, k.toUpperCase()]);
let obj2 = Object.fromEntries(keyValuePairs);
console.log(obj2); // { x: 'X', y: 'Y', z: 'Z' }
{ a: 1, b: 2 }
{ x: 'X', y: 'Y', z: 'Z' }
Пример 5: Свойство-аксессор с кэшированием вычислений
Геттер area хранит вычисленное значение, сбрасывая его при изменении зависимых свойств.
let rectangle = {
_width: 0,
_height: 0,
set width(w) { this._width = w; this._area = undefined; },
get width() { return this._width; },
set height(h) { this._height = h; this._area = undefined; },
get height() { return this._height; },
get area() {
if (this._area === undefined) {
this._area = this._width * this._height;
}
return this._area;
}
};
rectangle.width = 5;
rectangle.height = 3;
console.log(rectangle.area); // 15
rectangle.width = 7;
console.log(rectangle.area); // 21
15 21