JavaScript | Как проверить наличие объекта в массиве?

JavaScript | Как проверить наличие объекта в массиве?

Эту задачу можно понять несколькими смыслами:

  1. Мы в принципе хотим понять существует ли объект с фигурными скобками в массиве
  2. Мы хотим понять, есть ли похожий объект в массиве (с теми же ключами и значениями)

В этой публикации мы рассмотрим эти два варианта трактования вопроса. Начнём с простого.

 

Есть ли какой-то объект в массиве? Он существует в виде значения элемента этого массива?

Есть массив с одним объектом, одним массивом, числами и строками:

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 нашёл объект в массиве - JavaScript
Метод filter нашёл объект в массиве — JavaScript

Мы вызвали filter() и в ответ получили новый массив с одним элементом. Это как раз то что мы искали. Мы отловили в массиве какой-то объект.

Мы имеем новый массив длиной 1. Если бы в нашем оригинальном массиве небыло бы объектов, тогда фильтр вернул бы нам массив нулевой длины. Вот это и будет нашим условием существования какого либо объекта в массиве:

(massiv.filter(i => i.constructor.name == "Object").length > 0)
Условие существования объекта в массиве - JavaScript
Условие существования объекта в массиве — JavaScript

 

Получили ИСТИНУ (TRUE) значит в этом массиве есть объект.

Справка

Мы всегда можем распознать объект по его принадлежности к классу. В нашем случае:

  • фигурные скобки принадлежат классу Object,
  • квадратные скобки принадлежат классу Array,
  • числа принадлежат классу Number
  • строки принадлежат классу String

Давайте убедимся, что это так. Мы будем получать класс каждого элемента. То есть мы будем получать название конструктора, в котором был создан данный элемент массива.

massiv.map(i=>[i, i.constructor.name])
Получили имена конструкторов значений элементов массива и сопоставили - JavaScript
Получили имена конструкторов значений элементов массива и сопоставили — JavaScript

 

Есть ли похожий объект в массиве?

Есть массив:

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
Неравенство идентичных объектов - JavaScript
Неравенство идентичных объектов — JavaScript

Для кого-то это будет шок! Это значит, что мы не можем сравнивать объекты «в тупую» как они есть. Что делать?

Нужно привести объекты к строке и сравнивать строки. Поможет нам в этом конструктор JSON и его метод stringify(). В чём его слабость? В том, что он НЕ сортирует ключи перед упаковкой в строку. 🙂

Смотрим как это работает:

JSON.stringify({w:"Петров", s:"Петя"})
"{"w":"Петров","s":"Петя"}"

JSON.stringify({s:"Петя", w:"Петров"})
"{"s":"Петя","w":"Петров"}"

JSON.stringify({w:"Петров", s:"Петя"}) == JSON.stringify({s:"Петя", w:"Петров"})
false
JSON.stringify не сортирует свойства объектов - JavaScript
JSON.stringify не сортирует свойства объектов — JavaScript

 

Сейчас нам нужна функция, которая умеет сортировать свойства в объектах, до их передачи в stringify()

Мы можем сделать так:

  1. Конвертируем объект в массив
  2. Сортируем массив
  3. Переводим массив в строку
  4. Сравниваем строки

Поехали

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
Сравнили два объекта - получили true - JavaScript
Сравнили два объекта — получили true — JavaScript

Мы научились сравнивать объекты и теперь можем вернуться к нашему массиву и проверить есть ли в нём такой объект или нет.

Будем использовать тот же самый filter()

massiv.filter(i=>JSON.stringify(  Object.entries(i).sort()) == JSON.stringify(Object.entries({w: "Васильев", s:"Вася"}).sort())  )

 

Искомый объект есть в массиве - JavaScript
Искомый объект есть в массиве — JavaScript

Обе перестановки свойств вернули нам в фильтре нужный объект. Это значит, что такой объект существует в массиве. Мы его нашли.

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