Как сравнить объекты в Javascript
В Javascript нельзя просто взять и сравнить два объекта привычным способом: Obj1 === Obj2
. Такое выражение всегда вернёт false
. Всё дело в том, что объекты являются ссылочным типом данных и значение в них передаётся по ссылке. Следовательно, при сравнении объектов мы, по сути, сравниваем то, куда указывает их ссылка. А у разных объектов, даже если их содержимое идентично, ссылка указывает в разные места. Так как же нам сравнить объекты? Тут у нас есть 3 способа.
1. С помощью JSON.stringify
Тут всё довольно просто. Мы конвертируем объекты в строку и сравниваем полученные строки.
const object1 = { title: "Title", id: 1};const object2 = { title: "Title", id: 1};const object3 = { title: "Another title", id: 3};console.log(JSON.stringify(object1) === JSON.stringify(object2)); // trueconsole.log(JSON.stringify(object2) === JSON.stringify(object3)); // falseconsole.log(JSON.stringify(object1) === JSON.stringify(object3)); // false
Однако у этого метода есть некоторые ограничения. Например, если свойства объектов идут не в одном порядке, то сравнение вернёт false
.
const object1 = { title: "Title", id: 1};const object2 = { id: 1 title: "Title",};console.log(JSON.stringify(object1) === JSON.stringify(object2)); // false
2. С помощью библиотеки lodash
Можно вообще не париться и просто взять готовый инструмент. В библиотеке lodash есть метод _.isEqual
, который без проблем сравнивает объекты.
const object1 = { title: "Title", id: 1};const object2 = { id: 1 title: "Title",};console.log(_.isEqual(object1, object2)); // true
3. Написать свою функцию для сравнения объектов
Это, конечно, совершенно необязательно. Но для поддержания тонуса почему бы не попрактиковаться.
Первое, что приходит в голову — это составить список ключей объектов и сравнить их значения.
function isEqual(object1, object2) { const props1 = Object.getOwnPropertyNames(object1); const props2 = Object.getOwnPropertyNames(object2); if (props1.length !== props2.length) { return false; } for (let i = 0; i < props1.length; i += 1) { const prop = props1[i]; if (object1[prop] !== object2[prop]) { return false; } } return true;}const object1 = { title: "Title", id: 1};const object2 = { id: 1 title: "Title",};console.log(isEqual(object1, object2)); // true
Работает. Но есть одна проблема. Если у нас будет вложенный объект, то перестанет работать.
const object1 = { title: "Title", id: 1, price: { base: 100, vat: 20 }};const object2 = { id: 1 title: "Title", price: { base: 100, vat: 20 }};console.log(isEqual(object1, object2)); // false
Происходит это, потому что мы просто сравниваем значения ключей объектов. А когда значение само является объектом, то, естественно, простое сравнение всегда возвращает false
. Нужно как-то это предусмотреть.
function isEqual(object1, object2) { const props1 = Object.getOwnPropertyNames(object1); const props2 = Object.getOwnPropertyNames(object2); if (props1.length !== props2.length) { return false; } for (let i = 0; i < props1.length; i += 1) { const prop = props1[i]; const bothAreObjects = typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object'; if ((!bothAreObjects && (object1[prop] !== object2[prop])) || (bothAreObjects && !isEqual(object1[prop], object2[prop]))) { return false; } } return true;}
Вот теперь работает как надо и нам не страшны вложенные объекты. Если значения ключей являются объектами, то мы рекурсивно вызываем нашу функцию isEqual
.