Я недавно повторяла тему объектов и подумала, что кому-то может пригодиться мой конспект. Я очень советую писать конспекты, своими словами и юмором, чтобы закрепить понимание темы. Такая вот вариация на тему метода Фейнмана — "подбери мемас к тезису" :D
- Что такое объект
- Как обратиться к свойству
- Как модифицировать объект
- Ссылочная природа
- Как наполнять объект
- Как проверить наличие свойства
- Как обойти объект
- Слияние двух объектов
- Копирование объекта
Что такое объект
Все в мире можно описать через объект. Объектом в JS являются даже массивы и функции. Если новичок понимает объекты, то уже способен решать довольно сложные задачи. Я вот прям глубоко не понимаю, что такое объект, но наверное это со временем придет!
Как обратиться к свойству
Ключи в объекте называются свойствами. Далее мы будем использовать именно это слово. Чтобы не запутаться, я представляю себе ключ (key) с брелоком в виде дома (property):
Есть разные способы обратиться к свойству объекта. Но мы в любом случае в начале конструкции пишем название нашего объекта, а потом уже выбранным способом обращаемся к свойству из этого объекта.
Итак. Если объект больше не будет меняться, мы можем обратиться к свойству просто через точку. То есть мы пишем название объекта, ставим точку и дальше пишем название свойства. Эта конструкция вернет наружу значение переданного свойства.
user.name
А что, если объект будет меняться в течение жизни? Тогда мы поступаем следующим образом. Мы вместо того чтобы после имени объекта писать точку и имя свойства, убираем и то и другое. Мы пишем не точку, а открываем квадратные скобки. Внутри квадратных скобок мы пишем имя свойства, которое нас интересует, но в кавычках. Таким образом интерпретатор поймет, к какому свойству мы обращаемся, даже если имя свойства поменяется в процессе жизни объекта.
user['name']
Красоты ради мы можем сохранить имя свойства в виде строкового значения в какой-нибудь константе. Тогда мы пишем имя объекта, открываем квадратные скобки, но передаем не строковое значение имени свойства, а константу, в котором это имя записали.
user[propertyName]
Чтобы было совсем хорошо, мы можем очень красиво зафиксировать имена свойств в константах. Если мы только создаем новый объект, то делаем это так:
const user = { name, surname }
Маги высшего уровня могут позволить себе сделать так, чтобы имя константы и имя свойства были разными. Они просто ставят двоеточие и пишут имя константы, которое им нравится:
const user = { name: login, surname }
Это все замечательно, но что делать, если у нас вложенные объекты? С этим синтаксисом получится длинная такая колбаса:
const author = response.data.relationships.author;
Чтобы колбасы не было, можно использовать деструктуризацию. Но к ее записи надо привыкнуть...
Во-первых, при деструктуризации объекта наш "донор" расположен справа от знака равенства:
const person = { firstName: 'Rasmus', lastName: 'Lerdorf', manager: true };
const { firstName, manager } = person;
console.log(firstName); // => 'Rasmus'
console.log(manager); // => true
Из этого примера мы так же понимаем еще два момента. Первое: порядок извлечения свойств не важен. Второе: необязательно при деструктуризации извлекать все свойства.
Хорошо, теперь посмотрим, как деструктуризация помогает работать с вложенными объектами. Разберем пример:
// const user = response.data.attributes;
// const links = response.data.links;
// const author = response.data.relationships.author;
const { links, attributes: user, relationships: { author } } = response.data;
В комментарии расшифровка того, что происходит внутри константы. Тут нужно поводить пальчиком чтобы понять, откуда что берется, но оно того стоит.
Справа от знака равно наш "донор". Мы уже в него углубились на один уровень, на уровень data. Что мы берем у нашего донора?
- links забираем в одноименную константу без изменений.
- attributes нас не устраивает, поэтому мы даем константе другое название, название user, и в него записываем содержимое свойства attributes.
- author тут записан немного по-другому, потому что это вложенная деструктуризация. Если мы указываем фигурные скобки, то в author попадает всё под ключом author. Если не указываем, то это не вложенная деструктуризация и в author упадет всё под ключом relationships.
Чтобы не запутаться в том, откуда что берется, запомните: слева от двоеточия мы указываем свойство донора, справа от двоеточия мы указываем новое свойство, записанное в одноименную константу.
Советую понасоздавать своих объектов и выводить в консоль разные свойства, чтобы понять, как работает разный синтаксис.
Ещё раз про вложенную деструктуризацию (просто потому что до меня долго доходило):
const { relationships: author }
// то же самое что const author = response.data.relationships;
const { relationships: { author } }
// то же самое что const author = response.data.relationships.author;
Но это еще, к сожалению или к счастью, не все. Деструктуризация позволяет задавать значения по умолчанию! Ну, на тот случай, если мы попробуем взять у донора несуществующее свойство и не хотим, чтобы записалось undefined. Вот пример:
const person = { firstName: 'Rasmus', lastName: 'Lerdorf' };
console.log(person.manager); // undefined
const { manager = false } = person;
console.log(manager); // => false
Как модифицировать объект
Мы используем синтаксис присваивания, и когда хотим создать новое свойство, и когда хотим поменять старое свойство. Напоминаю, что синтаксис присваивания это два объекта, разделенные знаком равно (да ведь?). Разумеется при этом нам надо как-то обратиться к свойству — через квадратные кавычки или через точку. Вспоминаем предыдущий пункт.
Ссылочная природа
Ссылочная природа вытворяет чудеса в нескольких случаях. Во-первых, новая ссылка создается, даже когда мы просто объявляем пустой объект, не сохраняя его в константу. Поэтому два пустых объекта не будут равны.
Во-вторых, если клонировать объекты по умолчанию, то все вложенные объекты не будут клонированы, ссылки останутся теми же самыми. Перезапись вложенных свойств в клоне приведет к изменению этих свойств в оригинале.
Для того чтобы избежать этой участи, надо использовать методы, которые делают глубокое, а не поверхностное, клонирование.
Ну и в-третьих, ссылкам плевать на область видимости. Когда мы меняем свойство в одной области, оно по ссылке поменяется в другой области.
Как наполнять объект
Если есть возможность, наполняйте объект сразу. Но такой роскоши может не быть, если у нас сразу на руках нет всех данных для наполнения объекта.
Еще надо наполнять объект после проверки, если вы не уверены, что свойство окажется на своем месте. Ставьте проверку на наличие свойства.
Как проверить наличие свойства
Это очень объемная тема. Всего есть около шести способов, один более надежный чем прочие. Если коротко, то методы из стандартной библиотеки никому не нравятся. Их можно заменить функциями из библиотеки lodash. Также лодаш хорошо заменит операторов JS (проверьте меня тут пожалуйста).
Если надо вытащить на свет божий какое-нибудь вложенное свойство, но вы даже не уверены, там ли оно, используйте функцию _.get()
из лодаша. Эта функция достанет свойство, если оно есть, и не будет возвращать ошибку, если где-то свойства нет.
Она принимает первым аргументом объект для путешествия, вторым аргументом цепочку свойств, третьим аргументом стандартное значение, которое вернется, если свойства не обнаружилось.
Самое прекрасное что можно вторым аргументом передать цепочку динамических свойств. О том, как это сделать, написано в пункте Как обратиться к свойствам.
Среди других способов обратиться к свойству без проверок есть следующие:
- Оператор опциональной последовательности
- Оператор нулевого слияния
- Функция лодаша has()
- Метод JS hasOwnProperty
Подробно о каждом способе есть в уроках Хекслета:
Как обойти объект
Если надо что-то сделать со свойствами объекта, их записывают в массив и там работают. Закончив работу, создают новый объект или модифицируют старый.
Массив снимает и другую проблему. Массив располагает содержимое в определенном порядке, а объект делает что хочет. Поэтому если нас волнует порядок, используем массив.
Как мы помним, внутри объекта хранятся пары. В паре есть имя свойства и значение свойства. Стандартная библиотека JS позволяет работать как с целой парой, так и с ее частями.
- Метод Object.keys возвращает наружу все имена свойств.
- Метод Object.values возвращает наружу все значения свойств.
- Метод Object.entries возвращает наружу все пары целиком.
Все эти методы возвращают наружу массив. Массив удобно обойти и, как я уже говорила, массив, в отличие от метода, сохраняет строгий порядок значений.
Слияние двух объектов
Мы уже знаем, как обновить объект по одному свойству. А что если нам нужно добавить сразу много свойств? В этом случае мы говорим про слияние.
Самый удобный способ — это функция Object.assign(). Надо помнить, что она перезаписывает значения и что она выполняет только поверхностное слияние. Чем отличается поверхностное слияние? Читайте пункт "ссылочная природа". Если коротко, то вложенные объекты скопируются по ссылке. Меняете что-то в копии и упс, меняется оригинал.
Если вы не будете контролировать, что добавляете при слиянии, то ваш изначальный объект получит лишние свойства. Могут быть также затерты свойства, которые нужны — например, количество денег на счету пользователя.
Копирование объекта
Как мы уже знаем, надо создавать копию объекта, чтобы случайно не поломать оригинальный объект. Производительность не всегда позволяет это сделать, но для небольших объектов проблем нет.
Самый лучший способ сделать копию — использовать функцию _.cloneDeep()
из библиотеки lodash. Она сразу склонирует даже вложенные объекты.
О других способах читайте здесь:
У меня все!