</> Praktum

Главная / JavaScript / Объекты JavaScript

Урок · JavaScript

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

Редакция PraktumОбновлено 15 минут на урок с практикойУровень: новичок

Объект в JavaScript — набор пар «ключ — значение» в фигурных скобках, описывающий одну сущность: пользователя, товар, урок. Значение читают через точку lesson.title или квадратные скобки lesson['title']. Значением может быть что угодно, включая функцию — тогда это метод.

Коротко
  • { title: 'Flexbox', minutes: 20 } — объект из двух свойств.
  • Точка — для известного ключа, скобки — когда ключ в переменной.
  • Несуществующее свойство даёт undefined, а не ошибку.
  • const copy = obj не копирует объект — нужен { ...obj }.
  • Object.entries(obj) превращает объект в массив пар для перебора.

Зачем этот урок сейчас

У урока есть название, длительность, уровень и автор. Можно завести четыре переменные, но для десяти уроков их станет сорок. Объект собирает данные одной вещи вместе, а массив объектов — каталог целиком. Ответы сервера в JSON, настройки, состояние интерфейса — всё это объекты.

Создание и чтение

const lesson = {
  title: 'Flexbox',
  minutes: 20,
  isPublished: true,
  tags: ['css', 'layout'],
};

console.log(lesson.title);      // 'Flexbox'
console.log(lesson['minutes']); // 20

const field = 'isPublished';
console.log(lesson[field]);     // true — ключ из переменной
console.log(lesson.author);     // undefined — такого свойства нет

Ключи — строки, даже если записаны без кавычек. Кавычки обязательны, если в ключе пробел или дефис: { 'data-id': 5 }, и читать его тогда можно только через скобки.

Изменение, добавление и удаление

lesson.minutes = 25;          // изменить
lesson.level = 'начальный';   // добавить новое свойство
delete lesson.isPublished;    // удалить

'level' in lesson;            // true
Object.hasOwn(lesson, 'author'); // false

Объект, объявленный через const, можно менять изнутри: const запрещает только присвоить переменной другой объект. Проверить наличие ключа надёжнее через in или Object.hasOwn: сравнение с undefined не отличит отсутствующий ключ от ключа со значением undefined.

Короткая запись свойств

const title = 'Grid';
const minutes = 30;

const lesson = { title, minutes };     // то же, что { title: title, minutes: minutes }
const key = 'level';
const extra = { [key]: 'средний' };    // вычисляемый ключ: { level: 'средний' }

Методы и this

const cart = {
  items: [],
  add(product) {
    this.items.push(product);
  },
  total() {
    return this.items.reduce((sum, p) => sum + p.price, 0);
  },
};

cart.add({ title: 'Курс CSS', price: 1500 });
cart.total(); // 1500

Функция внутри объекта — метод. this в методе указывает на объект перед точкой при вызове: cart.add() — значит, this это cart. Методы пишут в короткой форме add() {}, а не стрелкой: у стрелочной функции нет своего this, и this.items внутри неё не сработает.

Деструктуризация

const { title, minutes, level = 'старт' } = lesson;

function showLesson({ title, minutes }) {
  return `${title}: ${minutes} минут`;
}
showLesson(lesson);

Деструктуризация достаёт несколько свойств в переменные одной строкой. Имена должны совпадать с ключами, а значение по умолчанию сработает, если свойства нет. Особенно удобно в параметрах функции: сразу видно, какие поля ей нужны.

Ссылка и копия

const a = { title: 'HTML', tags: ['base'] };
const b = a;                 // вторая ссылка на тот же объект
b.title = 'CSS';
console.log(a.title);        // 'CSS' — изменился и a

const copy = { ...a, title: 'JS' };   // поверхностная копия с заменой поля
copy.tags.push('new');                // но массив внутри общий!

const deep = structuredClone(a);      // глубокая копия

Переменная хранит не сам объект, а ссылку на него. Присваивание копирует ссылку. Spread создаёт новый объект, но вложенные массивы и объекты остаются общими. Когда нужно менять вложенные данные независимо, используй structuredClone.

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

const prices = { html: 0, css: 1500, js: 2500 };

Object.keys(prices);    // ['html', 'css', 'js']
Object.values(prices);  // [0, 1500, 2500]
Object.entries(prices); // [['html', 0], ['css', 1500], ['js', 2500]]

for (const [course, price] of Object.entries(prices)) {
  console.log(`${course}: ${price} ₽`);
}

Object.keys, values и entries превращают объект в массив, а массив уже можно перебрать, отфильтровать и отсортировать. Подробнее — на странице Object.keys, values и entries.

Безопасное чтение: ?. и ??

const user = { name: 'Анна' };

user.address.city;            // TypeError: нельзя читать city у undefined
user.address?.city;           // undefined — без ошибки
user.address?.city ?? 'Город не указан'; // запасное значение

Читать несуществующее свойство безопасно, а вот свойство у undefined — ошибка. Опциональная цепочка ?. останавливается на пустом звене. Оператор ?? подставляет запасное значение только для null и undefined, в отличие от ||, который заменит и 0, и пустую строку.

Массив объектов

const lessons = [
  { id: 1, title: 'HTML', done: true },
  { id: 2, title: 'CSS', done: false },
];

const current = lessons.find((l) => l.id === 2);
const done = lessons.filter((l) => l.done);
const titles = lessons.map((l) => l.title);

Однотипные данные хранят массивом объектов: так устроены каталоги, списки задач и почти все ответы сервера. Ищут нужный объект через find, отбирают через filter, преобразуют через map.

Объект или массив

Объект

Разные свойства одной сущности с именами: название, цена, автор урока. Доступ по ключу.

Массив

Список однотипных элементов по порядку: уроки, задачи, комментарии. Доступ по индексу, перебор и сортировка.

Частые ошибки

  • Читают свойство у undefined: user.address.city без проверки — используй ?..
  • Считают const copy = obj копией и случайно меняют общий объект.
  • Пишут метод стрелочной функцией и удивляются, что this не работает.
  • Путают точку и скобки: obj.key ищет ключ «key», а не значение переменной key.
  • Перебирают объект через for без Object.entries и получают ошибку «не итерируемый».

Доступность

Объекты — внутренняя структура программы, но часто из них строится интерфейс: карточки, списки, таблицы. Выводи данные объектов через textContent и правильные теги (список, таблица), а не склеивай HTML-строкой — так текст не сломает разметку и останется понятным скринридеру.

Поддержка браузерами

Объекты и базовые операции работают везде. Короткая запись свойств, деструктуризация и spread поддерживаются всеми актуальными браузерами. ?., ??, Object.hasOwn и structuredClone — более новые, но тоже доступны в актуальных версиях Chrome, Safari и Firefox.

Практика

Создай объект товара с названием, ценой и количеством. Добавь метод total(), возвращающий стоимость. Затем сделай копию товара с другим количеством, не меняя исходный объект, и выведи все свойства копии в консоль строками «ключ: значение».

Показать решение
const product = {
  title: 'Курс HTML',
  price: 1200,
  count: 1,
  total() {
    return this.price * this.count;
  },
};

const bigOrder = { ...product, count: 3 };
console.log(bigOrder.total()); // 3600
console.log(product.count);    // 1 — исходный не изменился

for (const [key, value] of Object.entries(bigOrder)) {
  if (typeof value !== 'function') console.log(`${key}: ${value}`);
}

Открыть песочницу

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

Чем точка отличается от квадратных скобок?

Точка читает свойство с фиксированным именем: obj.title. Скобки принимают строку или переменную: obj[key], и нужны для ключей с пробелами и дефисами.

Почему изменился исходный объект?

Переменные хранят ссылку на объект. const b = a не копирует его — обе переменные смотрят на один объект. Копию даёт { ...a } или structuredClone(a).

Как проверить, есть ли свойство в объекте?

'key' in obj или Object.hasOwn(obj, 'key'). Сравнение с undefined не отличит отсутствующий ключ от ключа со значением undefined.

Как перебрать объект?

Через Object.entries(obj) и for...of: for (const [key, value] of Object.entries(obj)).

Почему this в методе равен undefined?

Метод записан стрелочной функцией или вызван отдельно от объекта (например, передан в обработчик). Пиши методы в форме name() {} и вызывай через объект.

Источники