Объекты в JavaScript: создание и работа

Содержание

О проверке кода. Примеры не запускались — в отличие от материалов по Node.js с фактическим выводом. Говорим прямо, а не ставим бейдж «проверено».

Объект — главная структура данных JavaScript: почти всё в языке им является. Разберём создание, доступ и типовые операции без ловушек.

Создание объекта

// литерал — основной способ
const user = {
  name: 'Аня',
  age: 30,
  greet() { return `Привет, ${this.name}`; },   // метод
};

// пустой и потом заполнить
const empty = {};
empty.x = 1;

Литерал {} — то, чем создают объекты в 99% случаев. Ключи — строки (кавычки можно опускать для валидных имён), значения — что угодно, включая функции (методы) и вложенные объекты.

Доступ: точка против скобок

user.name;          // "Аня" — точка, когда имя известно
user['name'];       // то же самое

const key = 'age';
user[key];          // 30 — динамический доступ ТОЛЬКО через скобки
user['user-id'];    // скобки, если имя с дефисом или спецсимволом

Точка — когда имя свойства известно заранее и является валидным идентификатором. Квадратные скобки — обязательны в двух случаях: имя лежит в переменной (динамический доступ) или содержит символы, недопустимые в идентификаторе (user-id, пробелы).

Это ровно причина, по которой data-атрибуты в DOM и ключи с дефисами читают через скобки.

Вычисляемые ключи и сокращения

Современный синтаксис убирает повторы:

const name = 'Аня';
const age = 30;

// сокращённая запись: имя переменной = имя свойства
const user = { name, age };        // вместо { name: name, age: age }

// вычисляемый ключ — имя из выражения
const field = 'email';
const obj = { [field]: 'a@b.ru' };  // ключ будет "email"

// метод короче
const api = {
  get() {},                         // вместо get: function() {}
};

Сокращённая запись { name, age } — то, что вы постоянно видите при возврате объектов из функций. Вычисляемый ключ [field] позволяет задать имя свойства динамически прямо в литерале.

Перебор объекта

const user = { name: 'Аня', age: 30, city: 'Москва' };

Object.keys(user);      // ['name', 'age', 'city']
Object.values(user);    // ['Аня', 30, 'Москва']
Object.entries(user);   // [['name','Аня'], ['age',30], ['city','Москва']]

for (const [key, value] of Object.entries(user)) {
  console.log(key, value);
}
Перебор объекта: что чем

Object.keys / values / entries

Современный способ

  • Возвращают массив — можно map, filter
  • Только собственные свойства
  • entries + for...of для пар
  • Предсказуемо

for…in

Наследие, осторожно

  • Обходит и унаследованные свойства
  • Нужна проверка hasOwn внутри
  • Для массивов вообще не стоит
  • Заменён Object.keys

Берите Object.keys/values/entries — они возвращают массив (значит, доступны map, filter) и обходят только собственные свойства. Старый for...in обходит ещё и унаследованные из прототипа, что почти всегда не то, что нужно.

Копирование: поверхностное и глубокое

const original = { name: 'Аня', address: { city: 'Москва' } };

// поверхностная копия
const shallow = { ...original };
shallow.name = 'Борис';           // ✅ не тронет оригинал
shallow.address.city = 'Казань';  // ❌ address ОБЩИЙ — изменит оригинал!

// глубокая копия
const deep = structuredClone(original);
deep.address.city = 'Пермь';      // ✅ оригинал цел

{ ...obj } и Object.assign копируют только верхний уровень. Вложенные объекты остаются общими — меняете во «копии», меняется в оригинале. Это та же природа ссылок, что у массивов.

Для настоящей независимости — structuredClone(obj): он копирует всю структуру, включая Date, Map, Set. В отличие от старого трюка JSON.parse(JSON.stringify(obj)), который эти типы ломает. structuredClone — метод платформы, работает и в Node.

Проверка свойства

const user = { name: 'Аня', role: undefined };

'name' in user;                    // true — есть в цепочке (и унаследованное)
Object.hasOwn(user, 'name');       // true — только собственное
user.role !== undefined;           // false — но role ЕСТЬ, просто undefined!

Не проверяйте существование через сравнение с undefined — оно врёт, если значение и есть undefined. Надёжно: Object.hasOwn(obj, key) (собственное свойство) или оператор in (с учётом прототипа). Object.hasOwn — современная замена hasOwnProperty.

Защита объекта

const config = Object.freeze({ port: 3000 });
config.port = 8080;   // молча не сработает (в строгом режиме — ошибка)

Object.keys(config);  // читать можно

Object.freeze делает объект неизменяемым — ни изменить, ни добавить, ни удалить свойства. Полезно для констант-конфигов. Помните: const защищает переменную, а freeze — содержимое объекта; это разные вещи. И freeze тоже поверхностный — вложенные объекты нужно замораживать отдельно.


Смежные темы: примитивы и ссылки — почему копия общая; методы Object — подробнее; классы — когда объекта мало. Полный список — в уроках JavaScript.

Частые вопросы

Когда использовать точку, а когда квадратные скобки?
Точка — когда имя свойства известно и валидный идентификатор: obj.name. Скобки — когда имя в переменной или содержит спецсимволы: obj[key], obj[‘user-id’]. Динамический доступ возможен только через скобки.
Как перебрать свойства объекта?
Object.keys(obj) даёт массив ключей, Object.values — значений, Object.entries — пар [ключ, значение]. Для for…of берут entries. Старый for…in работает, но обходит и унаследованные свойства.
Как правильно скопировать объект?
Поверхностная копия — { …obj } или Object.assign({}, obj): вложенные объекты остаются общими. Глубокая копия — structuredClone(obj): копирует всё, включая Date и Map.
Как проверить, есть ли свойство в объекте?
Оператор in: ’name’ in obj — проверяет и унаследованные. obj.hasOwnProperty(’name’) или Object.hasOwn(obj, ’name’) — только собственные. Сравнение obj.name !== undefined ненадёжно, если значение и есть undefined.
Что такое сокращённая запись свойств?
Когда имя переменной совпадает с именем свойства, пишут один раз: { name } вместо { name: name }. Аналогично для методов: { greet() {} } вместо { greet: function() {} }.