Можно ли сравнить два объекта в JavaScript и как это сделать
Что проверяют
Понимаете ли вы, что встроенного сравнения по содержимому нет, и знаете ли ловушки обходных способов.
Как отвечать
Встроенные операторы сравнивают объекты по ссылке: два разных объекта с одинаковым содержимым не равны. Специальная функция сравнения тоже сравнивает ссылки, отличаясь от строгого равенства только обработкой особого числового значения и знака нуля.
Значит сравнение по содержимому надо делать самому. Способы:
1. Сериализация в строку. Соблазнительно коротко и полно ловушек:
- зависит от порядка ключей: два одинаковых по смыслу объекта дадут разные строки;
- теряет данные: функции, неопределённые значения и символы просто исчезают, специальное числовое значение превращается в пустое, дата становится строкой;
- бросает исключение на циклических ссылках.
Годится разве что для простых плоских данных, где вы контролируете форму.
2. Поверхностное сравнение. Сравнить набор ключей и значения по одному уровню. Дёшево и достаточно там, где вложенных объектов нет. Именно так сравнивает свойства React.
3. Глубокое рекурсивное сравнение. Обход с проверкой типов, учётом массивов, дат, регулярных выражений, словарей и множеств, а также защитой от циклических ссылок. Писать его самому в проекте обычно не стоит: готовая функция из известной библиотеки уже учла все случаи.
Что стоит добавить:
- стоимость: глубокое сравнение пропорционально размеру данных, и в горячем месте оно может обойтись дороже, чем то, ради чего затевалось. Часто дешевле сравнивать не объекты, а их идентификаторы или версию;
- неизменяемый подход снимает вопрос: если объект не меняется, а при изменении создаётся новый, достаточно сравнения по ссылке. Это и есть причина, по которой в React состояние не мутируют.
Где спотыкаются
Сравнивают объекты обычным равенством и удивляются результату.
Используют сериализацию и попадают на порядок ключей.
Пишут своё глубокое сравнение без учёта дат и особых значений.
Делают глубокое сравнение в часто вызываемом коде.