Вложенные объекты в JavaScript

В свойстве объекта может храниться не только строка, число или булево значение, но и другой объект.

let user = {
  name: 'Анна',
  contacts: {
    email: 'anna@example.com',
    phone: '+7 900 000-00-00',
  },
};

Здесь contacts - обычное свойство объекта user. Просто значением этого свойства является еще один объект.

Что такое вложенный объект

Вложенный объект используют, когда несколько свойств относятся к одной части данных.

let product = {
  title: 'Клавиатура',
  price: 2500,
  dimensions: {
    width: 45,
    height: 15,
    depth: 3,
  },
};

Свойства width, height и depth относятся к размерам товара. Поэтому их удобно хранить внутри свойства dimensions.

Доступ к вложенным свойствам

Чтобы обратиться к вложенному свойству, нужно идти по цепочке от внешнего объекта к внутреннему.

let user = {
  name: 'Анна',
  contacts: {
    email: 'anna@example.com',
  },
};

console.log(user.contacts.email); // anna@example.com

Сначала JavaScript получает user.contacts, а уже затем берет свойство email внутри объекта contacts.

Если уровней больше, цепочка просто становится длиннее.

let order = {
  customer: {
    address: {
      city: 'Москва',
    },
  },
};

console.log(order.customer.address.city); // Москва

Точка и квадратные скобки

При работе с вложенными объектами можно комбинировать точку и квадратные скобки.

let user = {
  name: 'Анна',
  contacts: {
    email: 'anna@example.com',
    'home city': 'Москва',
  },
};

console.log(user.contacts.email); // anna@example.com
console.log(user.contacts['home city']); // Москва

Квадратные скобки нужны, если имя свойства содержит пробел, дефис или хранится в переменной.

let user = {
  contacts: {
    email: 'anna@example.com',
  },
};

let section = 'contacts';
let field = 'email';

console.log(user[section][field]); // anna@example.com

Здесь section и field - переменные. Поэтому используются квадратные скобки.

Изменение вложенных свойств

Вложенное свойство изменяется так же, как обычное. Отличается только путь до него.

let user = {
  name: 'Анна',
  contacts: {
    email: 'anna@example.com',
  },
};

user.contacts.email = 'new@example.com';

console.log(user.contacts.email); // new@example.com

Мы не заменили весь объект user. Изменилось только значение свойства email внутри contacts.

Добавление вложенных свойств

Новое свойство можно добавить внутрь уже существующего вложенного объекта.

let user = {
  name: 'Анна',
  contacts: {
    email: 'anna@example.com',
  },
};

user.contacts.phone = '+7 900 000-00-00';

console.log(user.contacts);

Результат:

{
  email: 'anna@example.com',
  phone: '+7 900 000-00-00'
}

Если вложенный объект уже есть, можно спокойно добавлять в него новые свойства.

Если вложенного объекта нет

Нельзя добавить свойство внутрь объекта, которого нет.

let user = {
  name: 'Анна',
};

user.contacts.email = 'anna@example.com'; // ошибка

В этом примере свойства contacts нет. Поэтому JavaScript не может записать email внутрь undefined.

Сначала нужно создать вложенный объект, а потом добавить в него свойство.

let user = {
  name: 'Анна',
};

user.contacts = {};
user.contacts.email = 'anna@example.com';

console.log(user.contacts.email); // anna@example.com

Если нужно только прочитать значение, которое может отсутствовать, можно использовать опциональную цепочку ?..

let user = {
  name: 'Анна',
};

console.log(user.contacts?.email); // undefined

?. не создает свойство. Он только помогает безопасно прочитать данные, если часть цепочки может отсутствовать.

Глубокая вложенность

Вложенные объекты удобны, когда структура данных понятная.

let user = {
  name: 'Анна',
  profile: {
    social: {
      github: 'anna-dev',
    },
  },
};

console.log(user.profile.social.github); // anna-dev

Но если цепочки становятся слишком длинными, код сложнее читать и менять.

user.profile.settings.notifications.email.enabled

Такая структура иногда нужна, но с ней стоит быть аккуратнее. Чем глубже вложенность, тем чаще приходится проверять, есть ли промежуточные объекты.

Итого

  • Вложенный объект - это объект, который хранится в свойстве другого объекта.
  • К вложенным свойствам обращаются по цепочке: user.contacts.email.
  • Точку и квадратные скобки можно комбинировать.
  • Чтобы изменить или добавить вложенное свойство, промежуточный объект уже должен существовать.
  • Для безопасного чтения необязательных вложенных свойств можно использовать ?..
  • Слишком глубокая вложенность делает код менее удобным для чтения.