Объект — это набор именованных значений
Массив группирует значения по позиции, а объект javascript — по имени. Когда то, что вы моделируете, состоит из именованных частей — пользователь с именем и возрастом, запрос с методом и URL, — в дело идёт объект.
Самый короткий способ создать объект javascript — литерал объекта:
Каждая запись — это пара ключ: значение. Под капотом ключи всегда строки (кавычки можно опустить для валидных идентификаторов вроде name). А в значении может быть что угодно, с чем умеет работать JavaScript: числа, строки, булевы значения, массивы, функции и даже другие объекты.
Запятую после последнего элемента ставить можно. Большинство команд её оставляют — так при добавлении нового свойства в diff попадает только одна строка.
Чтение и запись свойств объекта
Обратиться к свойству можно двумя способами: через точку или через квадратные скобки.
Точечная нотация выглядит аккуратнее и обычно её берут по умолчанию. Нотация через квадратные скобки пригождается, когда ключ лежит в переменной или когда сам ключ — не валидный идентификатор:
Обращение к несуществующему свойству возвращает undefined — без всяких ошибок:
Так баги прячутся молча — опечатки проходят незамеченными. Если хочется, чтобы код падал с грохотом, проверку надо добавлять вручную.
Как добавить и удалить свойство объекта
Объекты в JavaScript открыты для правок — новые ключи можно докидывать когда угодно:
А удалить — через delete:
delete — оператор из тех, что в ежедневной работе встречаются редко, но когда нужно именно выкинуть ключ из объекта (а не просто присвоить ему undefined), без него никуда. Если написать user.email = undefined, сам ключ останется на месте — и "email" in user по-прежнему вернёт true.
Как проверить наличие свойства в объекте
Есть три способа, и у каждого свой нюанс:
inпроверяет наличие ключа, включая те, что унаследованы через цепочку прототипов.Object.hasOwn(obj, key)смотрит только на собственные ключи объекта. Используйте его, когда хотите проигнорировать унаследованное. Это современная замена устаревшемуhasOwnProperty.obj.key !== undefinedв большинстве случаев работает, но врёт, если свойству явно присвоено значениеundefined.
Если сомневаетесь — берите Object.hasOwn. Обычно он делает именно то, что вы имели в виду.
Методы: функции внутри объекта js
Свойство, значением которого является функция, называется методом. Для их объявления внутри литерала объекта есть короткий синтаксис:
this внутри метода ссылается на тот объект, на котором метод был вызван — в нашем случае это user. Именно так greet понимает, чьё имя подставлять.
Важный момент: у стрелочных функций нет собственного this, поэтому для методов, которым нужно обращаться к другим свойствам объекта, они не подходят:
Короткий синтаксис методов (greet() { ... }) используйте везде, где внутри встречается this. Стрелочные функции — отличный выбор для колбэков, но не для методов объекта.
Вложенные объекты js
Значением свойства тоже может быть объект — и так сколько угодно уровней вглубь:
Чтение вложенного свойства работает по цепочке — 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:
Object.entries — самый удобный способ: сразу получаешь и ключ, и значение, а в паре с деструктуризацией массива выходит вообще красиво.
Есть ещё цикл for...in, но он проходит и по унаследованным свойствам, а это обычно не то, что нужно:
for (const key in scores) {
console.log(key); // работает, но включает унаследованные ключи
}
Используй Object.keys / Object.entries, если тебе не нужны унаследованные свойства.
Сокращённый синтаксис, который стоит знать
Немного синтаксического сахара, который встречается буквально на каждом шагу:
Сокращённая запись свойств срабатывает, когда имя переменной совпадает с ключом. Вычисляемые ключи (синтаксис [expr]) позволяют формировать имена свойств динамически — удобно, когда пишешь функцию, которая обновляет поле по его имени.
Сравнение объектов идёт по ссылке
На этом спотыкаются практически все хотя бы раз:
=== применительно к объектам проверяет, ссылаются ли обе стороны на один и тот же объект в памяти, а не совпадает ли их содержимое. Два объекта с одинаковыми свойствами — это по-прежнему два разных объекта.
Если нужно ответить на вопрос «одинаковой ли они формы?», придётся сравнивать поля вручную или подключить хелпер для глубокого сравнения. JSON.stringify(a) === JSON.stringify(b) — это быстрый костыль, который нормально работает на простых данных, но ломается, как только появляются функции, undefined или циклические ссылки.
Объекты JavaScript мутабельны даже с const
const фиксирует за переменной одно значение. Но сам объект, на который она указывает, он не замораживает:
Если действительно нужна неизменяемость, поможет 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 особенно удобен, когда на каждой итерации нужны и ключ, и значение сразу.