Как определить равенство для двух объектов JavaScript?

Оператор строгого равенства скажет вам, если два типа объектов равны. Однако есть ли способ определить, равны ли два объекта, так же, как значение хэш-кода в Java?

Вопрос переполнения стека Есть ли какая-либо функция hashCode в JavaScript? похож на этот вопрос, но требует более академического ответа. Сценарий выше демонстрирует, почему это необходимо, и мне интересно, есть ли какое-либо эквивалентное решение.

88 ответов

Решение

Краткий ответ

Ответ прост: нет, нет универсальных средств для определения того, что объект равен другому в том смысле, который вы имеете в виду. Исключение составляют случаи, когда вы строго думаете о том, что объект не имеет типов.

Длинный ответ

Концепция заключается в методе Equals, который сравнивает два разных экземпляра объекта, чтобы указать, равны ли они на уровне значения. Тем не менее, это зависит от конкретного типа, чтобы определить, как Equals метод должен быть реализован. Итеративного сравнения атрибутов, которые имеют примитивные значения, может быть недостаточно, вполне могут быть атрибуты, которые не следует рассматривать как часть значения объекта. Например,

 function MyClass(a, b)
 {
     var c;
     this.getCLazy = function() {
         if (c === undefined) c = a * b // imagine * is really expensive
         return c;
     }
  }

В этом случае выше, c не очень важно определить, равны ли любые два экземпляра MyClass, только a а также b важные. В некоторых случаях c может варьироваться между экземплярами и все же не быть значимым при сравнении.

Обратите внимание, что эта проблема применима, когда члены сами могут быть экземплярами типа, и каждый из них должен иметь средства определения равенства.

Еще более усложняется то, что в JavaScript различие между данными и методами размыто.

Объект может ссылаться на метод, который должен вызываться как обработчик события, и это, вероятно, не будет считаться частью его "состояния значения". Тогда как другому объекту вполне может быть назначена функция, которая выполняет важные вычисления и тем самым отличает этот экземпляр от других просто потому, что ссылается на другую функцию.

Как насчет объекта, у которого один из существующих методов-прототипов переопределен другой функцией? Можно ли считать его равным другому экземпляру, который в остальном идентичен? На этот вопрос можно ответить только в каждом конкретном случае для каждого типа.

Как указывалось ранее, исключение будет представлять собой объект строго типизированного типа. В этом случае единственный разумный выбор - итеративное и рекурсивное сравнение каждого члена. Даже тогда нужно спросить, какова "ценность" функции?

Зачем изобретать велосипед? Дайте Лодаш попробовать. Он имеет ряд обязательных функций, таких как isEqual ().

_.isEqual(object, other);

Он будет грубо проверять каждое значение ключа - как и другие примеры на этой странице - используя ECMAScript 5 и встроенную оптимизацию, если они доступны в браузере.

Примечание. Ранее этот ответ рекомендовал http://underscorejs.org/, но lodash проделал лучшую работу по исправлению ошибок и последовательному решению проблем.

Оператор равенства по умолчанию в JavaScript для объектов возвращает true, если они ссылаются на одно и то же место в памяти.

var x = {};
var y = {};
var z = x;

x === y; // => false
x === z; // => true

Если вам нужен другой оператор равенства, вам нужно добавить equals(other) метод, или что-то вроде этого для ваших классов и специфика вашей проблемной области будет определять, что именно это означает.

Вот пример игральной карты:

function Card(rank, suit) {
  this.rank = rank;
  this.suit = suit;
  this.equals = function(other) {
     return other.rank == this.rank && other.suit == this.suit;
  };
}

var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");

queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true

Короткий функционал deepEqual реализация:

function deepEqual(x, y) {
  return (x && y && typeof x === 'object' && typeof y === 'object') ?
    (Object.keys(x).length === Object.keys(y).length) &&
      Object.keys(x).reduce(function(isEqual, key) {
        return isEqual && deepEqual(x[key], y[key]);
      }, true) : (x === y);
}

Изменить: версия 2, используя предложение стрелы и функции стрелки ES6:

function deepEqual(x, y) {
  const ok = Object.keys, tx = typeof x, ty = typeof y;
  return x && y && tx === 'object' && tx === ty ? (
    ok(x).length === ok(y).length &&
      ok(x).every(key => deepEqual(x[key], y[key]))
  ) : (x === y);
}

Это моя версия. Он использует новую функцию Object.keys, которая представлена ​​в ES5, и идеи / тесты из +, + и +:

function objectEquals(x, y) {
    'use strict';

    if (x === null || x === undefined || y === null || y === undefined) { return x === y; }
    // after this just checking type of one would be enough
    if (x.constructor !== y.constructor) { return false; }
    // if they are functions, they should exactly refer to same one (because of closures)
    if (x instanceof Function) { return x === y; }
    // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES)
    if (x instanceof RegExp) { return x === y; }
    if (x === y || x.valueOf() === y.valueOf()) { return true; }
    if (Array.isArray(x) && x.length !== y.length) { return false; }

    // if they are dates, they must had equal valueOf
    if (x instanceof Date) { return false; }

    // if they are strictly equal, they both need to be object at least
    if (!(x instanceof Object)) { return false; }
    if (!(y instanceof Object)) { return false; }

    // recursive object equality check
    var p = Object.keys(x);
    return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) &&
        p.every(function (i) { return objectEquals(x[i], y[i]); });
}


///////////////////////////////////////////////////////////////
/// The borrowed tests, run them by clicking "Run code snippet"
///////////////////////////////////////////////////////////////
var printResult = function (x) {
    if (x) { document.write('<div style="color: green;">Passed</div>'); }
    else { document.write('<div style="color: red;">Failed</div>'); }
};
var assert = { isTrue: function (x) { printResult(x); }, isFalse: function (x) { printResult(!x); } }
assert.isTrue(objectEquals(null,null));
assert.isFalse(objectEquals(null,undefined));
assert.isFalse(objectEquals(/abc/, /abc/));
assert.isFalse(objectEquals(/abc/, /123/));
var r = /abc/;
assert.isTrue(objectEquals(r, r));

assert.isTrue(objectEquals("hi","hi"));
assert.isTrue(objectEquals(5,5));
assert.isFalse(objectEquals(5,10));

assert.isTrue(objectEquals([],[]));
assert.isTrue(objectEquals([1,2],[1,2]));
assert.isFalse(objectEquals([1,2],[2,1]));
assert.isFalse(objectEquals([1,2],[1,2,3]));

assert.isTrue(objectEquals({},{}));
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));

assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

Object.prototype.equals = function (obj) { return objectEquals(this, obj); };
var assertFalse = assert.isFalse,
    assertTrue = assert.isTrue;

assertFalse({}.equals(null));
assertFalse({}.equals(undefined));

assertTrue("hi".equals("hi"));
assertTrue(new Number(5).equals(5));
assertFalse(new Number(5).equals(10));
assertFalse(new Number(1).equals("1"));

assertTrue([].equals([]));
assertTrue([1,2].equals([1,2]));
assertFalse([1,2].equals([2,1]));
assertFalse([1,2].equals([1,2,3]));
assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31")));
assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01")));

assertTrue({}.equals({}));
assertTrue({a:1,b:2}.equals({a:1,b:2}));
assertTrue({a:1,b:2}.equals({b:2,a:1}));
assertFalse({a:1,b:2}.equals({a:1,b:3}));

assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

var a = {a: 'text', b:[0,1]};
var b = {a: 'text', b:[0,1]};
var c = {a: 'text', b: 0};
var d = {a: 'text', b: false};
var e = {a: 'text', b:[1,0]};
var i = {
    a: 'text',
    c: {
        b: [1, 0]
    }
};
var j = {
    a: 'text',
    c: {
        b: [1, 0]
    }
};
var k = {a: 'text', b: null};
var l = {a: 'text', b: undefined};

assertTrue(a.equals(b));
assertFalse(a.equals(c));
assertFalse(c.equals(d));
assertFalse(a.equals(e));
assertTrue(i.equals(j));
assertFalse(d.equals(k));
assertFalse(k.equals(l));

// from comments on stackru post
assert.isFalse(objectEquals([1, 2, undefined], [1, 2]));
assert.isFalse(objectEquals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }));
assert.isFalse(objectEquals(new Date(1234), 1234));

// no two different function is equal really, they capture their context variables
// so even if they have same toString(), they won't have same functionality
var func = function (x) { return true; };
var func2 = function (x) { return true; };
assert.isTrue(objectEquals(func, func));
assert.isFalse(objectEquals(func, func2));
assert.isTrue(objectEquals({ a: { b: func } }, { a: { b: func } }));
assert.isFalse(objectEquals({ a: { b: func } }, { a: { b: func2 } }));

Если вы работаете в AngularJS, angular.equals Функция определит, равны ли два объекта. В Ember.js используйте isEqual,

  • angular.equals - Смотрите документы или источник для получения дополнительной информации об этом методе. Это делает глубокое сравнение на массивах тоже.
  • ember.js isEqual - Смотрите документы или источник для получения дополнительной информации об этом методе. Это не делает глубокое сравнение на массивах.

var purple = [{"purple": "drank"}];
var drank = [{"purple": "drank"}];

if(angular.equals(purple, drank)) {
    document.write('got dat');
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>

Если вы используете библиотеку JSON, вы можете закодировать каждый объект как JSON, а затем сравнить полученные строки на равенство.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

ПРИМЕЧАНИЕ. Хотя этот ответ будет работать во многих случаях, как отметили несколько человек в комментариях, это проблематично по ряду причин. В большинстве случаев вы захотите найти более надежное решение.

Для тех из вас, кто использует NodeJS, есть удобный метод isDeepStrictEqual на родной библиотеке Util, которая может достичь этого.

const util = require('util');

const foo = {
  hey: "ho",
  lets: "go"
}

const bar = {
  hey: "ho",
  lets: "go"
}

foo == bar // false
util.isDeepStrictEqual(foo, bar) // true

https://nodejs.org/api/util.html

В Node.js вы можете использовать его нативный require("assert").deepEqual, Дополнительная информация: http://nodejs.org/api/assert.html

Например:

var assert = require("assert");
assert.deepEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError

Еще один пример, который возвращает true / false вместо возврата ошибок:

var assert = require("assert");

function deepEqual(a, b) {
    try {
      assert.deepEqual(a, b);
    } catch (error) {
      if (error.name === "AssertionError") {
        return false;
      }
      throw error;
    }
    return true;
};

На этот вопрос уже более 30 ответов. Я собираюсь резюмировать и объяснять их (аналогией с "моим отцом") и добавлять свое предлагаемое решение.

У вас есть 4+1 класса решений:


1) Используйте хакерский неполный быстрый однострочник

Хорошо, если вы торопитесь и работает 99% корректности.

Примеры этого: JSON.stringify()предложенный Pratik Bhalodiya, илиJSON.encode Джоэл Анаир или другой.toString() или другие методы, которые преобразуют ваши объекты в строку, а затем сравнивают две строки, используя === персонаж за персонажем.

Однако недостатком является отсутствие глобально стандартного уникального представления объекта в строке. например{ a: 5, b: 8} а также {b: 8 and a: 5 } равны.

  • Плюсы: Быстро, быстро.
  • Минусы: Надеюсь, работает! Совершенно не гарантируется. На больших объектах производительность тоже была бы невысокой.

Моя аналогия с отцом

Когда я говорю о своем отце, "мой высокий красивый отец" и "мой красивый высокий отец" - это одно и то же лицо! Но эти две струны не одно и то же.

Обратите внимание, что на самом деле существует правильный (стандартный) порядок прилагательных в грамматике английского языка, который гласит, что это должен быть "красивый высокий мужчина", но вы рискуете своей компетентностью, если слепо предполагаете, что движок Javascript в iOS 8 Safari также соблюдает та же грамматика, вслепую! #WelcomeToJavascriptNonStandards


2) Напишите свою собственную рекурсивную функцию DIY

Хорошо, если учишься.

Примеры - решение atmin.

The biggest disadvantage is you will definitely miss some edge cases. Have you considered a self-reference in object values? Have you considered NaN? Have you considered two objects that have the same ownProperties but different prototypical parents?

I would only encourage people to do this if they are practicing and the code is not going to go in production. That's the only case that reinventing the wheel has justifications.

  • Pros: Learning opportunity.
  • Cons: Not reliable. Takes time and concerns.

My Father Analogy

It's like assuming if my dad's name is "John Smith" and his birthday is "1/1/1970", then anyone whose name is "John Smith" and is born on "1/1/1970" is my father.

That's usually the case, but what if there are two "John Smith"s born on that day? If you think you will consider their height, then that's increasing the accuracy but still not a perfect comparison.

2.1 You limited scope DIY comparator

Rather than going on a wild chase of checking all the properties recursively, one might consider checking only "a limited" number of properties. For instance, if the objects are Users, you can compare their emailAddress field.

It's still not a perfect one, but the benefits over solution #2 are:

  1. It's predictable, and it's less likely to crash.
  2. You are driving the "definition" of equality, rather than relying on a wild form and shape of the Object and its prototype and nested properties.

3) Use a library version of equal function

Хорошо, если вам нужно качество на уровне производства, и вы не можете изменить дизайн системы.

Примеры _.equal lodash, уже в ответе coolaj86 или Angular или Ember, как указано в ответе Тони Харви или Node от Рафаэля Ксавьера.

  • Плюсы: это то, что делают все остальные.
  • Минусы: внешняя зависимость, которая может стоить вам дополнительной памяти / процессора / безопасности, даже немного. Кроме того, все еще могут быть пропущены некоторые крайние случаи (например, есть ли у двух объектов одинаковыеownPropertiesно разные прототипы родителей должны рассматриваться как одни и те же или нет.) Наконец, вы можете непреднамеренно связать с этим основную проблему дизайна; просто говорю!

Моя аналогия с отцом

Это все равно что платить агентству за поиск моего биологического отца по его телефону, имени, адресу и т. Д.

Это будет стоить дороже и, вероятно, точнее, чем я проверяю биографические данные, но не охватывает крайних случаев, например, когда мой отец является иммигрантом / убежищем и его день рождения неизвестен!


4) Используйте IDentifier в объекте

Хорошо, если вы [все еще] можете изменить дизайн системы (объекты, с которыми вы имеете дело) и хотите, чтобы ваш код работал долго.

Это применимо не во всех случаях и может быть не очень эффективным. Однако это очень надежное решение, если оно у вас есть.

Решение состоит в том, чтобы каждый objectв системе будет иметь уникальный идентификатор вместе со всеми другими свойствами. Уникальность идентификатора будет гарантирована в момент генерации. И вы будете использовать этот идентификатор (также известный как UUID/GUID - глобальный / универсальный уникальный идентификатор), когда дело доходит до сравнения двух объектов. т.е. они равны тогда и только тогда, когда эти идентификаторы равны.

Идентификаторы могут быть простыми auto_incrementalчисла или строка, созданная с помощью библиотеки (рекомендуется) или фрагмента кода. Все, что вам нужно сделать, это убедиться, что он всегда уникален, что в случаеauto_incremental он может быть встроенным или, в случае UUID, может проверяться все существующие значения (например, MySQL UNIQUE column attribute) или просто (если исходят из библиотеки) полагаться на чрезвычайно низкую вероятность коллизии.

Обратите внимание, что вам также необходимо постоянно хранить идентификатор с объектом (чтобы гарантировать его уникальность), и вычисление его в реальном времени может быть не лучшим подходом.

  • Плюсы: Надежный, экономичный, не грязный, современный.
  • Минусы: требуется дополнительное пространство. Возможно, потребуется переработка системы.

Моя аналогия с отцом

Это похоже на то, что номер социального страхования моего отца - 911-345-9283, так что любой, у кого есть этот номер социального страхования, является моим отцом, и любой, кто утверждает, что он мой отец, должен иметь этот номер социального страхования.


Вывод

Я лично предпочитаю решение №4 (ID) всем им по точности и надежности. Если это невозможно, я бы выбрал № 2.1 для предсказуемости, а затем № 3. Если ни то, ни другое невозможно, выберите №2 и, наконец, №1.

Вы пытаетесь проверить, равны ли два объекта? т.е. их свойства равны?

Если это так, вы, вероятно, заметили эту ситуацию:

var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"

вам, возможно, придется сделать что-то вроде этого:

function objectEquals(obj1, obj2) {
    for (var i in obj1) {
        if (obj1.hasOwnProperty(i)) {
            if (!obj2.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    for (var i in obj2) {
        if (obj2.hasOwnProperty(i)) {
            if (!obj1.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    return true;
}

Очевидно, что эта функция могла бы выполнять довольно большую оптимизацию и иметь возможность выполнять глубокую проверку (для обработки вложенных объектов: var a = { foo : { fu : "bar" } }) Но ты получил идею.

Как указывалось в FOR, вам, возможно, придется адаптировать это для ваших собственных целей, например: разные классы могут иметь разные определения "равно". Если вы просто работаете с простыми объектами, выше может быть достаточно, в противном случае пользовательский MyClass.equals() Функция может быть путь.

Простейшие и логичные решения для сравнения всего, как Object, Array, String, Int...

JSON.stringify({a: val1}) === JSON.stringify({a: val2})

Замечания:

  • вам нужно заменить val1а также val2 с вашим объектом
  • для объекта, вы должны отсортировать (по ключу) рекурсивно для обоих сторонних объектов

Если у вас есть функция глубокого копирования, вы можете использовать следующий трюк, чтобы по- прежнему использовать JSON.stringify при сопоставлении порядка свойств:

function equals(obj1, obj2) {
    function _equals(obj1, obj2) {
        return JSON.stringify(obj1)
            === JSON.stringify($.extend(true, {}, obj1, obj2));
    }
    return _equals(obj1, obj2) && _equals(obj2, obj1);
}

Демо: http://jsfiddle.net/CU3vb/3/

Обоснование:

Так как свойства obj1 копируются в клон по одному, их порядок в клоне будет сохранен. И когда свойства obj2 копируются в клон, так как свойства, уже существующие в obj1 будут просто перезаписаны, их заказы в клоне будут сохранены.

var object1 = {name: "humza" , gender : "male", age: 23}
var object2 = {name: "humza" , gender : "male", age: 23}
var result = Object.keys(object1).every((key) =>  object1[key] === object2[key])

Результат будет истинным, если объект1 имеет такие же значения на объекте2.

Я использую это comparable функция для создания копий моих объектов, которые сопоставимы с JSON:

var comparable = o => (typeof o != 'object' || !o)? o :
  Object.keys(o).sort().reduce((c, key) => (c[key] = comparable(o[key]), c), {});

// Demo:

var a = { a: 1, c: 4, b: [2, 3], d: { e: '5', f: null } };
var b = { b: [2, 3], c: 4, d: { f: null, e: '5' }, a: 1 };

console.log(JSON.stringify(comparable(a)));
console.log(JSON.stringify(comparable(b)));
console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b)));
<div id="div"></div>

Пригодится в тестах (большинство тестовых фреймворков имеют is функция). Например

is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');

Если разница обнаружена, строки регистрируются, что делает различия заметными:

x must match y
got      {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.

Вот решение ESES /ES2015, основанное на функциональном стиле:

const typeOf = x => 
  ({}).toString
      .call(x)
      .match(/\[object (\w+)\]/)[1]

function areSimilar(a, b) {
  const everyKey = f => Object.keys(a).every(f)

  switch(typeOf(a)) {
    case 'Array':
      return a.length === b.length &&
        everyKey(k => areSimilar(a.sort()[k], b.sort()[k]));
    case 'Object':
      return Object.keys(a).length === Object.keys(b).length &&
        everyKey(k => areSimilar(a[k], b[k]));
    default:
      return a === b;
  }
}

демо доступно здесь

Я не знаю, публиковал ли кто-нибудь что-нибудь похожее на это, но вот функция, которую я сделал для проверки равенства объектов.

function objectsAreEqual(a, b) {
  for (var prop in a) {
    if (a.hasOwnProperty(prop)) {
      if (b.hasOwnProperty(prop)) {
        if (typeof a[prop] === 'object') {
          if (!objectsAreEqual(a[prop], b[prop])) return false;
        } else {
          if (a[prop] !== b[prop]) return false;
        }
      } else {
        return false;
      }
    }
  }
  return true;
}

Кроме того, он рекурсивный, поэтому он также может проверять глубокое равенство, если вы так его называете.

ES6: Минимальный код, который я мог бы сделать, - это. Он выполняет глубокое рекурсивное сравнение путем преобразования всех объектов в строку, единственное ограничение - отсутствие сравнения методов или символов.

const compareObjects = (a, b) => { 
  let s = (o) => Object.entries(o).sort().map(i => { 
     if(i[1] instanceof Object) i[1] = s(i[1]);
     return i 
  }) 
  return JSON.stringify(s(a)) === JSON.stringify(s(b))
}

console.log(compareObjects({b:4,a:{b:1}}, {a:{b:1},b:4}));

Ниже приведена короткая реализация, в которой ключи используются, но сортируются, как здесь предлагает @Jor .

Некоторые тесты были взяты из ответа @EbrahimByagowi здесь .

Конечно, используя JSON.stringifyрешение ограничено JSON-сериализуемыми типами (строка, число, объект JSON, массив, логическое значение, null). Объекты вроде Date, Functionи т. д. не поддерживаются.

Простое решение этой проблемы, которое многие не понимают, - это сортировка строк JSON (по символам). Это также обычно быстрее, чем другие решения, упомянутые здесь:

function areEqual(obj1, obj2) {
    var a = JSON.stringify(obj1), b = JSON.stringify(obj2);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}

Еще одна полезная вещь в этом методе - вы можете фильтровать сравнения, передавая функцию "replacer" в функции JSON.stringify ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). Следующее будет сравнивать только все ключи объектов, которые называются "сумасшедший":

function areEqual(obj1, obj2, filter) {
    var a = JSON.stringify(obj1, filter), b = JSON.stringify(obj2, filter);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}
var equal = areEqual(obj1, obj2, function(key, value) {
    return (key === 'derp') ? value : undefined;
});

Ты можешь использовать _.isEqual(obj1, obj2) из библиотеки underscore.js.

Вот пример:

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

Смотрите официальную документацию здесь: http://underscorejs.org/

JSON.stringify() работает для глубоких и неглубоких объектов обоих типов, не очень уверенных в аспектах производительности:

var object1 = {
  key: "value"
};

var object2 = {
  key: "value"
};

var object3 = {
  key: "no value"
};

console.log('object1 and object2 are equal: ', JSON.stringify(object1) === JSON.stringify(object2));

console.log('object2 and object3 are equal: ', JSON.stringify(object2) === JSON.stringify(object3));

Просто хотел представить свою версию сравнения объектов, используя некоторые функции es6. Заказ не учитывается. После преобразования всех if/else в троичные я получил следующее:

function areEqual(obj1, obj2) {

    return Object.keys(obj1).every(key => {

            return obj2.hasOwnProperty(key) ?
                typeof obj1[key] === 'object' ?
                    areEqual(obj1[key], obj2[key]) :
                obj1[key] === obj2[key] :
                false;

        }
    )
}

Если вы используете ES6+ через Babel или иным образом, вы также можете использовать Object.is(x, y),

Ссылка: http://wiki.ecmascript.org/doku.php?id=harmony:egal

Я нашел один простой способ сравнить значения двух объектов javascript , игнорируя порядок свойств, с помощью функции замены строки JSON:

      const compareReplacer = (key, value) => {
    if(typeof value === 'object' && !(value instanceof Array))
        return Object.entries(value).sort();
    return value;
}
export const compareObjects = (a, b) => JSON.stringify(a, compareReplacer) === JSON.stringify(b, compareReplacer);

Это упорядочит свойства на каждом этапе пути, так что результат строки будет инвариантным к порядку свойств. Кто-то, вероятно, делал это раньше, но я просто решил поделиться этим, если нет :).

      let std1 = {
  name: "Abhijeet",
  roll: 1
}

let std2 = {
  name: "Siddharth",
  roll: 2
}

console.log(JSON.stringify(std1) === JSON.stringify(std2))

Короче говоря, это проверит равенство двух переменных независимо от типа.

      function isSame (obj1, obj2) {
  const obj1Keys = Object.keys(obj1)
  const obj2Keys = Object.keys(obj2)

  return obj1Keys.length === obj2Keys.length && obj1Keys.every((key) => obj1[key] === obj2[key])
}

Я бы посоветовал не использовать хэширование или сериализацию (как предлагает решение JSON). Если вам нужно проверить, равны ли два объекта, вам нужно определить, что означает "равно". Может случиться так, что все элементы данных в обоих объектах совпадают, или может случиться так, что области памяти должны совпадать (имеется в виду, что обе переменные ссылаются на один и тот же объект в памяти), или может быть, что только один элемент данных в каждом объекте должен соответствовать.

Недавно я разработал объект, конструктор которого создает новый идентификатор (начиная с 1 и увеличивая на 1) каждый раз, когда создается экземпляр. Этот объект имеет функцию isEqual, которая сравнивает это значение id со значением id другого объекта и возвращает true, если они совпадают.

В этом случае я определил "равно" как означающее совпадение значений идентификатора. Учитывая, что каждый экземпляр имеет уникальный идентификатор, это можно использовать для реализации идеи, что соответствующие объекты также занимают одно и то же место в памяти. Хотя это не обязательно.

Метод Object.is() определяет, являются ли два значения одинаковыми.

Синтаксис

Object.is(value1, value2);

параметры

значение1: первое значение для сравнения.

значение2: второе значение для сравнения.

Возвращаемое значение

Логическое значение, указывающее, являются ли два аргумента одним и тем же значением.

Примеры

Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var test = { a: 1 };
Object.is(test, test);       // true

Object.is(null, null);       // true

// Special Cases
Object.is(0, -0);            // false
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

если вы хотите больше информации, прочитайте эту ссылку

Я вижу ответы кода спагетти. Без использования сторонних библиотек это очень просто.

Сначала отсортируйте два объекта по ключу, указав их ключевые имена.

let objectOne = { hey, you }
let objectTwo = { you, hey }

// If you really wanted you could make this recursive for deep sort.
const sortObjectByKeyname = (objectToSort) => {
    return Object.keys(objectToSort).sort().reduce((r, k) => (r[k] = objectToSort[k], r), {});
}

let objectOne = sortObjectByKeyname(objectOne)
let objectTwo = sortObjectByKeyname(objectTwo)

Затем просто используйте строку, чтобы сравнить их.

JSON.stringify(objectOne) === JSON.stringify(objectTwo)
Другие вопросы по тегам