Эту задачу можно понять несколькими смыслами:
- Мы в принципе хотим понять существует ли объект с фигурными скобками в массиве
- Мы хотим понять, есть ли похожий объект в массиве (с теми же ключами и значениями)
В этой публикации мы рассмотрим эти два варианта трактования вопроса. Начнём с простого.
Есть ли какой-то объект в массиве? Он существует в виде значения элемента этого массива?
Есть массив с одним объектом, одним массивом, числами и строками:
var massiv = [1, 2, 3, {a:"a"}, [777], 4, 5, "efim360.ru", "javascript"]
Проверим существование какого-либо объекта в массиве при помощи метода filter(). Внутрь метода filter() мы будем передавать анонимную функцию, которая будет возвращать нам true или false по заданному условию. Если будет true, то элемент попадёт в новый массив, если false, то не попадёт.
Т. к. мы имеем дело с прототипами классов, то условие сравнения будет определяться при помощи «имени конструктора», в котором этот элемент был создан. В качестве цели будет выбран класс Object, а его имя конструктора будет строкой «Object«. Не перепутайте, а то не получится. Мы сравниваем строки!
massiv.filter(i => i.constructor.name == "Object")
Мы вызвали filter() и в ответ получили новый массив с одним элементом. Это как раз то что мы искали. Мы отловили в массиве какой-то объект.
Мы имеем новый массив длиной 1. Если бы в нашем оригинальном массиве небыло бы объектов, тогда фильтр вернул бы нам массив нулевой длины. Вот это и будет нашим условием существования какого либо объекта в массиве:
(massiv.filter(i => i.constructor.name == "Object").length > 0)
Получили ИСТИНУ (TRUE) значит в этом массиве есть объект.
Справка
Мы всегда можем распознать объект по его принадлежности к классу. В нашем случае:
- фигурные скобки принадлежат классу Object,
- квадратные скобки принадлежат классу Array,
- числа принадлежат классу Number
- строки принадлежат классу String
Давайте убедимся, что это так. Мы будем получать класс каждого элемента. То есть мы будем получать название конструктора, в котором был создан данный элемент массива.
massiv.map(i=>[i, i.constructor.name])
Есть ли похожий объект в массиве?
Есть массив:
var massiv = [{w: "Васильев", s:"Вася"}, {s:"Петя", w:"Петров"}, 1, 2, 3, 4, 5]
Именно в таком виде, где свойства объектов W и S идут не по порядку.
Предположим, что мы хотим узнать существование объекта {w:»Петров», s:»Петя»} в массиве. Как это сделать?
Давайте с «подводных камней». Как вам такое условие?
{w:"Петров", s:"Петя"} == {w:"Петров", s:"Петя"} false
{w:"Петров", s:"Петя"} === {w:"Петров", s:"Петя"} false
Для кого-то это будет шок! Это значит, что мы не можем сравнивать объекты «в тупую» как они есть. Что делать?
Нужно привести объекты к строке и сравнивать строки. Поможет нам в этом конструктор JSON и его метод stringify(). В чём его слабость? В том, что он НЕ сортирует ключи перед упаковкой в строку. 🙂
Смотрим как это работает:
JSON.stringify({w:"Петров", s:"Петя"}) "{"w":"Петров","s":"Петя"}" JSON.stringify({s:"Петя", w:"Петров"}) "{"s":"Петя","w":"Петров"}" JSON.stringify({w:"Петров", s:"Петя"}) == JSON.stringify({s:"Петя", w:"Петров"}) false
Сейчас нам нужна функция, которая умеет сортировать свойства в объектах, до их передачи в stringify()
Мы можем сделать так:
- Конвертируем объект в массив
- Сортируем массив
- Переводим массив в строку
- Сравниваем строки
Поехали
JSON.stringify(Object.entries({w:"Петров", s:"Петя"}).sort()) "[["s","Петя"],["w","Петров"]]" JSON.stringify(Object.entries({s:"Петя", w:"Петров"}).sort()) "[["s","Петя"],["w","Петров"]]" JSON.stringify(Object.entries({w:"Петров", s:"Петя"}).sort()) == JSON.stringify(Object.entries({s:"Петя", w:"Петров"}).sort()) true
Мы научились сравнивать объекты и теперь можем вернуться к нашему массиву и проверить есть ли в нём такой объект или нет.
Будем использовать тот же самый filter()
massiv.filter(i=>JSON.stringify( Object.entries(i).sort()) == JSON.stringify(Object.entries({w: "Васильев", s:"Вася"}).sort()) )
Обе перестановки свойств вернули нам в фильтре нужный объект. Это значит, что такой объект существует в массиве. Мы его нашли.
massiv.filter(i=>JSON.stringify( Object.entries(i).sort()) == JSON.stringify(Object.entries({w: "Васильев", s:"Вася"}).sort()) ).length > 0 true
Задача выполнена!
Информационные ссылки
JavaScript | Равенство объектов
JavaScript | Как узнать экземпляром какого класса является объект?
Стандарт ECMAScript — Раздел «25.5 The JSON Object» — https://tc39.es/ecma262/#sec-json-object