Menu
Русский

Объекты в JavaScript: свойства и методы

Разбираемся, как устроены объекты в JavaScript: создание, чтение и запись свойств, добавление методов и приёмы, которые помогают держать код в порядке.

Объект — это набор именованных значений

Массив группирует значения по позиции, а объект javascript — по имени. Когда то, что вы моделируете, состоит из именованных частей — пользователь с именем и возрастом, запрос с методом и URL, — в дело идёт объект.

Самый короткий способ создать объект javascript — литерал объекта:

index.js
Output
Click Run to see the output here.

Каждая запись — это пара ключ: значение. Под капотом ключи всегда строки (кавычки можно опустить для валидных идентификаторов вроде name). А в значении может быть что угодно, с чем умеет работать JavaScript: числа, строки, булевы значения, массивы, функции и даже другие объекты.

Запятую после последнего элемента ставить можно. Большинство команд её оставляют — так при добавлении нового свойства в diff попадает только одна строка.

Чтение и запись свойств объекта

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

index.js
Output
Click Run to see the output here.

Точечная нотация выглядит аккуратнее и обычно её берут по умолчанию. Нотация через квадратные скобки пригождается, когда ключ лежит в переменной или когда сам ключ — не валидный идентификатор:

index.js
Output
Click Run to see the output here.

Обращение к несуществующему свойству возвращает undefined — без всяких ошибок:

index.js
Output
Click Run to see the output here.

Так баги прячутся молча — опечатки проходят незамеченными. Если хочется, чтобы код падал с грохотом, проверку надо добавлять вручную.

Как добавить и удалить свойство объекта

Объекты в JavaScript открыты для правок — новые ключи можно докидывать когда угодно:

index.js
Output
Click Run to see the output here.

А удалить — через delete:

index.js
Output
Click Run to see the output here.

delete — оператор из тех, что в ежедневной работе встречаются редко, но когда нужно именно выкинуть ключ из объекта (а не просто присвоить ему undefined), без него никуда. Если написать user.email = undefined, сам ключ останется на месте — и "email" in user по-прежнему вернёт true.

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

Есть три способа, и у каждого свой нюанс:

index.js
Output
Click Run to see the output here.
  • in проверяет наличие ключа, включая те, что унаследованы через цепочку прототипов.
  • Object.hasOwn(obj, key) смотрит только на собственные ключи объекта. Используйте его, когда хотите проигнорировать унаследованное. Это современная замена устаревшему hasOwnProperty.
  • obj.key !== undefined в большинстве случаев работает, но врёт, если свойству явно присвоено значение undefined.

Если сомневаетесь — берите Object.hasOwn. Обычно он делает именно то, что вы имели в виду.

Методы: функции внутри объекта js

Свойство, значением которого является функция, называется методом. Для их объявления внутри литерала объекта есть короткий синтаксис:

index.js
Output
Click Run to see the output here.

this внутри метода ссылается на тот объект, на котором метод был вызван — в нашем случае это user. Именно так greet понимает, чьё имя подставлять.

Важный момент: у стрелочных функций нет собственного this, поэтому для методов, которым нужно обращаться к другим свойствам объекта, они не подходят:

index.js
Output
Click Run to see the output here.

Короткий синтаксис методов (greet() { ... }) используйте везде, где внутри встречается this. Стрелочные функции — отличный выбор для колбэков, но не для методов объекта.

Вложенные объекты js

Значением свойства тоже может быть объект — и так сколько угодно уровней вглубь:

index.js
Output
Click Run to see the output here.

Чтение вложенного свойства работает по цепочке — user.address.city. Подвох в том, что если хоть одно звено в этой цепочке окажется null или undefined, вы получите TypeError:

console.log(user.profile.city);
// TypeError: Cannot read properties of undefined (reading 'city')

Опциональная цепочка (user.profile?.city) — современный способ это обойти: вместо ошибки получаем undefined, если какого-то звена в цепочке нет. Подробнее разберём её дальше в этой главе на отдельной странице.

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

Когда нужно пройтись по всем ключам объекта, на помощь приходит троица Object.keys, Object.values и Object.entries:

index.js
Output
Click Run to see the output here.

Object.entries — самый удобный способ: сразу получаешь и ключ, и значение, а в паре с деструктуризацией массива выходит вообще красиво.

Есть ещё цикл for...in, но он проходит и по унаследованным свойствам, а это обычно не то, что нужно:

for (const key in scores) {
  console.log(key);  // работает, но включает унаследованные ключи
}

Используй Object.keys / Object.entries, если тебе не нужны унаследованные свойства.

Сокращённый синтаксис, который стоит знать

Немного синтаксического сахара, который встречается буквально на каждом шагу:

index.js
Output
Click Run to see the output here.

Сокращённая запись свойств срабатывает, когда имя переменной совпадает с ключом. Вычисляемые ключи (синтаксис [expr]) позволяют формировать имена свойств динамически — удобно, когда пишешь функцию, которая обновляет поле по его имени.

Сравнение объектов идёт по ссылке

На этом спотыкаются практически все хотя бы раз:

index.js
Output
Click Run to see the output here.

=== применительно к объектам проверяет, ссылаются ли обе стороны на один и тот же объект в памяти, а не совпадает ли их содержимое. Два объекта с одинаковыми свойствами — это по-прежнему два разных объекта.

Если нужно ответить на вопрос «одинаковой ли они формы?», придётся сравнивать поля вручную или подключить хелпер для глубокого сравнения. JSON.stringify(a) === JSON.stringify(b) — это быстрый костыль, который нормально работает на простых данных, но ломается, как только появляются функции, undefined или циклические ссылки.

Объекты JavaScript мутабельны даже с const

const фиксирует за переменной одно значение. Но сам объект, на который она указывает, он не замораживает:

index.js
Output
Click Run to see the output here.

Если действительно нужна неизменяемость, поможет Object.freeze(user) — он запретит дальнейшие изменения (но только на верхнем уровне: вложенные объекты всё равно можно менять). На практике в большинстве проектов обходятся договорённостями вместо Object.freeze — воспринимайте объекты, объявленные через const, как «не переприсваивать эту переменную», а вопросы неизменяемости решайте уже на уровне архитектуры.

Дальше: массивы

Объекты и массивы — это два кирпичика, из которых складывается всё остальное в JavaScript. Объекты хранят данные с именованными полями, массивы — упорядоченные последовательности. В следующей главе разберём, как устроены массивы в JavaScript, и познакомимся с горсткой методов (push, slice, map и компания), которые тянут на себе львиную долю работы.

Часто задаваемые вопросы

Как создать объект в JavaScript?

Самый ходовой способ — литерал объекта: const user = { name: 'Ada', age: 30 }. В фигурных скобках перечисляем пары ключ-значение через запятую. Ключи — это строки (кавычки можно опустить, если ключ — валидный идентификатор), а значением может быть что угодно: число, строка, массив, функция или другой объект.

В чём разница между точечной и скобочной записью?

user.name и user['name'] делают одно и то же, когда ключ известен заранее. Скобки нужны в трёх случаях: ключ лежит в переменной (user[key]), содержит символы, которые точка не переварит (пробелы, дефисы), или начинается с цифры. Во всех остальных ситуациях точечная запись короче и читается приятнее.

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

Оператор 'name' in user проверяет наличие ключа, включая унаследованные. Object.hasOwn(user, 'name') смотрит только на собственные свойства объекта — это современная замена для hasOwnProperty. Можно ещё написать user.name !== undefined, но такая проверка соврёт, если свойству явно присвоили undefined.

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

Классика — for (const key in obj), но он захватывает и унаследованные ключи. На практике чаще берут Object.keys(obj), Object.values(obj) или Object.entries(obj) и прогоняют результат через for...of либо .forEach(). Object.entries особенно удобен, когда на каждой итерации нужны и ключ, и значение сразу.

Учитесь программировать с Coddy

НАЧАТЬ