> Можно ли сравнить два объекта в JavaScript и как это сделать (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: X5Tech
Стек: JavaScript
> Пример ответа
Короткий ответ
Да, сравнить два объекта в JavaScript можно, но напрямую через == или === нельзя - они сравнивают ссылки, а не содержимое. Для сравнения по значению нужно либо вручную обойти ключи, либо использовать JSON.stringify, либо сторонние утилиты вроде lodash.isEqual. Выбор зависит от структуры объектов, наличия вложенности, методов и порядка ключей. Встроенного глубокого сравнения в языке нет.
Подробное объяснение
При сравнении объектов операторы == и === проверяют, указывают ли обе переменные на один и тот же объект в памяти. Это сравнение по ссылке. Если два объекта имеют идентичные свойства и значения, но созданы отдельно, они не равны.
Для сравнения по содержимому нужно реализовать собственную логику или использовать готовые решения. Основные подходы:
- Поверхностное сравнение - сравниваются только собственные перечисляемые свойства первого уровня. Подходит для плоских объектов без вложенности.
- Глубокое сравнение - рекурсивно обходит все вложенные объекты и массивы, учитывая типы значений,
NaN,Date,RegExp,Map,Setи другие. - Сериализация -
JSON.stringifyпревращает объект в строку, после чего строки сравниваются. Минусы: порядок ключей влияет на результат,undefined, функции и символы теряются, циклические ссылки вызывают ошибку.
Также стоит учитывать прототипы: два объекта с одинаковыми свойствами, но разными прототипами формально не равны, если сравнивать через Object.getPrototypeOf.
На практике
Для большинства реальных задач достаточно JSON.stringify, если объекты плоские и порядок ключей стабилен. Но для сложных структур лучше использовать проверенные библиотеки, например lodash.isEqual, которая покрывает edge cases: NaN, Date, регулярные выражения, Map, Set, циклические ссылки.
Если хочется без зависимостей, пишут собственную функцию глубокого сравнения. Она должна:
- проверять ссылочное равенство первым делом;
- сравнивать типы и конструкторы;
- обрабатывать примитивы, включая
NaN; - рекурсивно обходить объекты, массивы,
Map,Set; - учитывать порядок ключей или игнорировать его (обычно игнорируют);
- защищаться от циклических ссылок через
WeakMapилиSet.
Пример кода
JAVASCRIPTfunction deepEqual(a, b, seen = new WeakMap()) {// Ссылочное равенство или одинаковые примитивыif (a === b) return true;// Обработка NaNif (typeof a === 'number' && typeof b === 'number' && Number.isNaN(a) && Number.isNaN(b)) {return true;}// Оба должны быть объектамиif (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {return false;}// Проверка циклических ссылокif (seen.has(a)) {return seen.get(a) === b;}seen.set(a, b);// Сравнение конструкторовif (a.constructor !== b.constructor) return false;// Dateif (a instanceof Date) {return a.getTime() === b.getTime();}// RegExpif (a instanceof RegExp) {return a.source === b.source && a.flags === b.flags;}// Mapif (a instanceof Map) {if (a.size !== b.size) return false;for (const [key, value] of a) {if (!b.has(key) || !deepEqual(value, b.get(key), seen)) return false;}return true;}// Setif (a instanceof Set) {if (a.size !== b.size) return false;for (const value of a) {if (![...b].some(v => deepEqual(value, v, seen))) return false;}return true;}// Массивыif (Array.isArray(a)) {if (a.length !== b.length) return false;for (let i = 0; i < a.length; i++) {if (!deepEqual(a[i], b[i], seen)) return false;}return true;}// Обычные объектыconst keysA = Object.keys(a);const keysB = Object.keys(b);if (keysA.length !== keysB.length) return false;for (const key of keysA) {if (!Object.prototype.hasOwnProperty.call(b, key)) return false;if (!deepEqual(a[key], b[key], seen)) return false;}return true;}// Пример использованияconst obj1 = { name: 'Alice', nested: { age: 30, tags: ['a', 'b'] } };const obj2 = { name: 'Alice', nested: { age: 30, tags: ['a', 'b'] } };console.log(deepEqual(obj1, obj2)); // true
Как отвечать на собеседовании
Начни с того, что прямое сравнение через == или === работает только по ссылке. Затем упомяни три подхода: поверхностное сравнение, глубокое сравнение и сериализацию. Объясни trade-off каждого: JSON.stringify прост, но не учитывает порядок ключей и теряет специальные типы. Глубокое сравнение - универсально, но требует аккуратности с циклическими ссылками и типами. Если используешь библиотеки, назови lodash.isEqual как стандарт де-факто. Покажи, что понимаешь edge cases: NaN, Date, Map, Set, прототипы. Если кандидат senior, ожидается, что он предложит собственную реализацию и объяснит её ограничения.
Что проверяет интервьюер
Интервьюер оценивает:
- понимание разницы между сравнением по ссылке и по значению;
- знание встроенных возможностей языка и их ограничений;
- умение проектировать рекурсивные алгоритмы;
- внимание к деталям: типы,
NaN, циклические ссылки, порядок ключей; - способность выбирать подходящий инструмент под задачу, а не писать велосипед там, где хватит
JSON.stringify; - знакомство с экосистемой (например,
lodash).
Типичные ошибки
- Использование
==или===для сравнения содержимого объектов - результат всегдаfalseдля разных ссылок. - Сравнение через
JSON.stringifyбез учёта порядка ключей - объекты с одинаковыми данными, но разным порядком свойств будут неравны. - Игнорирование
NaN-NaN !== NaN, поэтому прямое сравнение чисел дастfalse. - Забывают про циклические ссылки - рекурсивная функция уходит в бесконечный цикл.
- Не учитывают специальные типы:
Date,RegExp,Map,Set- сравнение черезObject.keysдля них не работает корректно. - Сравнивают только собственные свойства, забывая про унаследованные - хотя обычно это ожидаемое поведение, но стоит оговорить.
- Не проверяют конструкторы - объект и массив с одинаковыми ключами могут быть признаны равными, хотя это разные типы.
> Похожие задачи по frontend
В чем отличие массивов от объектов в JavaScript
Какие способы выполнения HTTP-запросов в браузере на JavaScript?
В чем отличие передачи параметров по значению и по ссылке в JavaScript?
Как сборщик мусора находит неиспользуемые объекты в JavaScript
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью