Как сравнить объекты в Javascript
В Javascript нельзя просто взять и сравнить два объекта привычным способом: Obj1 === Obj2
. Такое выражение всегда вернёт false
. Всё дело в том, что объекты являются ссылочным типом данных и значение в них передаётся по ссылке. Следовательно, при сравнении объектов мы, по сути, сравниваем то, куда указывает их ссылка. А у разных объектов, даже если их содержимое идентично, ссылка указывает в разные места. Так как же нам сравнить объекты? Тут у нас есть 3 способа.
JSON.stringify
1. С помощью Тут всё довольно просто. Мы конвертируем объекты в строку и сравниваем полученные строки.
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)); // true
console.log(JSON.stringify(object2) === JSON.stringify(object3)); // false
console.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
.