Как сравнивать объекты в JavaScript

Albert Saitov
3 min readMar 25, 2021

--

В JavaScript объекты всегда хранятся по ссылке. Это означает, что один объект строго равен другому, только если они оба указывают на один и тот же объект в памяти.

const o1 = { answer: 42 };
const o2 = o1;
const o3 = { answer: 42 };

o1 === o2; // true, ссылаются на один объект
o1 === o3; // false, разные ссылки, но идентичные свойства и значения свойств

Однако что, если вы хотите проверить, имеют ли два объекта идентичные ключи и значения? Есть 3 подхода.

Сравнить ключи и значения на прямую

Один простой подход - перебрать каждый ключ и значение в двух объектах и проверить их равенство.

const o1 = { question: null, answer: 42 };
const o2 = { question: null, answer: 42 };

objectsEqual(o1, o2); // true
objectsEqual(o1, { answer: 43 }); // false

function objectsEqual(o1, o2) {
const entries1 = Object.entries(o1);
const entries2 = Object.entries(o2);
if (entries1.length !== entries2.length) {
return false;
}
for (let i = 0; i < entries1.length; ++i) {
// Ключи
if (entries1[i][0] !== entries2[i][0]) {
return false;
}
// Значения
if (entries1[i][1] !== entries2[i][1]) {
return false;
}
}

return true;
}

Использовать JSON.stringify()

В предыдущем методе показано, как сравнивать объекты, проверяя, строго ли равны ключи и значения двух объектов. Но что, если одно из значений ключа — объект?

const o1 = { name: { first: 'Arthur', lastName: 'Dent' }, planet: 'Earth' };
const o2 = { name: { first: 'Arthur', lastName: 'Dent' }, planet: 'Earth' };

objectsEqual(o1, o2); // false, потому что `o1.name !== o2.name`

Вы можете сделать objectsEqual() рекурсивным, но в таком случае нужно быть осторожным с бесконечной рекурсией. Простой способ сравнить, являются ли два POJO полностью равными, — это сравнить их представления JSON с помощью JSON.stringify()

const o1 = { name: { first: 'Arthur', lastName: 'Dent' }, planet: 'Earth' };
const o2 = { name: { first: 'Arthur', lastName: 'Dent' }, planet: 'Earth' };

JSON.stringify(o1) === JSON.stringify(o2); // true

delete o2.planet;
JSON.stringify(o1) === JSON.stringify(o2); // false

Функция JSON.stringify() имеет несколько ограничений, которые делают ее не универсальным выбором для проверки полного равенства. Во-первых, важен порядок определения свойств:

const o1 = { question: null, answer: 42 };
const o2 = { answer: 42, question: null };
JSON.stringify(o1) === JSON.stringify(o2); // false

Во-вторых, не все типы могут быть представлены в JSON. Функция JSON.stringify() преобразует даты в строки и игнорирует ключи, значения которых не определены, что может привести к неожиданным результатам.

const o1 = { myDate: new Date('2016-06-01'), otherProperty: undefined };
const o2 = { myDate: '2016-01-01T00:00:00.000Z' };

JSON.stringify(o1) === JSON.stringify(o2); // false

Использовать Lodash isEqual()

isEqual() — это наиболее изощренный способ сравнения двух объектов. Он обрабатывает широкий спектр крайних случаев и избегает многих ошибок предыдущих двух подходов.

const obj1 = {
date: new Date('2020/06/01'),
num: new Number(1)
};
const obj2 = {
date: new Date('2020/06/01'),
num: 1
};

_.isEqual(obj1, obj2); // true
const obj1 = { name: 'Will Riker', rank: 'Commander' };

class Character {}
const obj2 = new Character();
Object.assign(obj2, { name: 'Will Riker', rank: 'Commander' });

_.isEqual(obj1, obj2); // false

Функция также достаточно хорошо избегает бесконечных рекурсий

const obj1 = {};
const obj2 = {};

obj1.circular = obj1;
obj2.circular = obj1;

_.isEqual(obj1, obj2); // true

Если вы уже используете Lodash, isEqual() — лучший способ сравнения, двух объектов. Первый подход хорош для случаев, когда вы не беспокоитесь о вложенных объектах, а JSON.stringify () может помочь обеспечить грубую глубокую проверку равенства в тех случаях, когда вы не можете использовать Lodash. Но, если вы можете использовать Lodash, isEqual() — лучший подход для сравнения двух объектов.

Данная статья является любительской адаптацией машинного перевода статьи https://masteringjs.io/tutorials/fundamentals/compare-objects

Спасибо за внимание…

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Albert Saitov
Albert Saitov

Written by Albert Saitov

Frontend разработчик, топлю за JavaScript и документоориентированные СУБД

No responses yet

Write a response