如何确定两个JavaScript对象的相等性?

时间:2008-10-14 13:41:07

标签: javascript object equals hashcode

严格相等运算符会告诉您两个对象类型是否相等。但是,有没有办法判断两个对象是否相等,与Java中的哈希码值非常相似?

Stack Overflow问题 Is there any kind of hashCode function in JavaScript? 与此问题类似,但需要更多学术答案。上面的场景说明了为什么需要有一个,我想知道是否有任何等效解决方案

73 个答案:

答案 0 :(得分:451)

为什么重新发明轮子?试试Lodash。它有许多必备功能,例如isEqual()

_.isEqual(object, other);

它将强制检查每个键值 - 就像本页上的其他示例一样 - 使用ECMAScript 5和本机优化(如果它们在浏览器中可用)。

注意:此前此答案建议使用Underscore.js,但lodash更好地修复了错误并解决了问题的一致性。

答案 1 :(得分:159)

简短回答

简单的答案是:不,没有通用的方法来确定一个对象在你的意思上是否与另一个对象相等。例外情况是您严格考虑对象是无类型的。

答案很长

概念是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的任何两个实例是否相等并不重要,只有ab很重要。在某些情况下,c可能会因实例而异,但在比较期间却不显着。

请注意,当成员本身也可能是某种类型的实例时,这个问题也适用,并且这些实例都需要具有确定相等性的方法。

更复杂的是,在JavaScript中,数据和方法之间的区别很模糊。

对象可以引用一个被称为事件处理程序的方法,这可能不会被视为其“值状态”的一部分。而另一个对象可能会被分配一个执行重要计算的函数,从而使该实例与其他对象不同,因为它引用了不同的函数。

如果某个对象的某个现有原型方法被另一个函数覆盖了?是否仍然可以认为它与其他实例相同?这个问题只能在每种类型的每个特定情况下得到解答。

如前所述,异常将是严格无类型的对象。在这种情况下,唯一明智的选择是每个成员的迭代和递归比较。即使这样,人们也要问一个函数的“价值”是什么?

答案 2 :(得分:145)

JavaScript for Objects中的默认相等运算符在引用内存中的相同位置时产生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

答案 3 :(得分:71)

如果您在AngularJS工作,angular.equals函数将确定两个对象是否相等。在Ember.js中使用isEqual

  • angular.equals - 有关此方法的详情,请参阅docssource。它也对数组进行了深入的比较。
  • Ember.js isEqual - 有关此方法的详情,请参阅docssource。它没有对数组进行深入比较。

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>

答案 4 :(得分:58)

这是我的版本。它使用了ES5中引入的新Object.keys功能以及+++中的提示/测试:

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 stackoverflow 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 } }));

答案 5 :(得分:47)

如果您使用的是JSON库,则可以将每个对象编码为JSON,然后比较生成的字符串是否相等。

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

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

注意:虽然这个答案在许多情况下都会有效,但有几个人在评论中指出,出于各种原因这是有问题的。在几乎所有情况下,您都希望找到更强大的解决方案。

答案 6 :(得分:31)

短期功能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,使用jib的建议和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);
}

答案 7 :(得分:20)

如果你有一个深层复制功能,你可以使用以下技巧仍然使用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中已存在的属性将被覆盖,因此将保留克隆中的订单。

答案 8 :(得分:17)

你是否试图测试两个物体是否相等?即:他们的财产是平等的?

如果是这种情况,您可能已经注意到了这种情况:

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()功能可能就好了。

答案 9 :(得分:17)

用于比较所有内容的

最简单逻辑解决方案,如对象,数组,字符串,整数...

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

注意:

  • 您需要将val1val2替换为您的对象
  • 对于对象,您必须递归(按键)对两个侧对象
  • 进行排序

答案 10 :(得分:16)

在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;
};

答案 11 :(得分:12)

我使用这个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函数)。 E.g。

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}}.

答案 12 :(得分:6)

您可以使用underscore.js库中的_.isEqual(obj1, obj2)

以下是一个例子:

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/#isEqual

答案 13 :(得分:6)

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上具有相同的值,则

结果将为 true

答案 14 :(得分:6)

我不知道是否有人发布了与此相似的内容,但这是我检查对象平等的一项功能。

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;
}

此外,它是递归的,因此它也可以检查深度相等,如果这是你所谓的。

答案 15 :(得分:5)

许多人没有意识到的这个问题的简单解决方案是对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#Example_of_using_replacer_parameter)来过滤比较。以下内容仅比较名为“derp”的所有对象键:

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;
});

答案 16 :(得分:5)

如果您通过Babel或其他方式使用ES6+,您还可以使用Object.is(x, y)

参考:http://wiki.ecmascript.org/doku.php?id=harmony:egal#object.is_x_y

答案 17 :(得分:4)

此问题已经有30多个答案。我将用“我的父亲”类比来总结和解释它们,并添加我建议的解决方案。

您有 4 + 1类解决方案


1)使用骇人的不完整快速单线纸

如果您赶时间并且正确率达到99%,那就很好。

例如,JSON.stringify()建议by Pratik BhalodiyaJSON.encode by Joel Anair或其他.toString()或将您的对象转换为String然后将其转换为其他方法的示例使用===逐个字符比较两个字符串。

但是,缺点是String中没有对象的全局标准唯一表示。例如{ a: 5, b: 8}{b: 8 and a: 5 }相等。

  • 优点:快速,快捷。
  • 缺点: 希望有效!完全不能保证。在大型物体上的性能也不是很好。

我父亲的比喻

当我谈论父亲时,“ 我的高个子帅哥”和“ 我的高个子帅哥”是同一个人!但是两个字符串不一样。

请注意,英语语法中的形容词实际上有一个正确的(标准方式)顺序,其中says应该是一个“英俊的高个子”,但您可能要冒自己的才能如果您盲目地认为iOS 8 Safari的Javascript引擎也盲目遵守相同的语法! #WelcomeToJavascriptNonStandards


2)编写自己的DIY递归函数

如果您正在学习,那就很好。

示例为atmin's solution

最大的缺点是您肯定会错过一些边缘情况。您是否考虑过对象值中的self-reference?您是否考虑过NaN?您是否考虑过两个ownProperties相同但原型父代不同的对象?

我只会鼓励人们在实践中这样做并且代码不会投入生产。这是重新发明轮子的唯一理由。

  • 优点:学习机会。
  • 缺点:不可靠。需要时间和关注。

我父亲的比喻

这就像假设我父亲的名字是“约翰·史密斯”并且他的生日是“ 1/1/1970”,那么以“约翰·史密斯”和“ 1/1/1970”出生的人是我的父亲

通常是这样,但是如果那天有两个“约翰·史密斯”出生怎么办?如果您认为自己会考虑它们的高度,那么虽然可以提高准确性,但仍然不是一个完美的比较。

2.1您有限范围的DIY比较器

人们可能会考虑只检查“有限”数量的属性,而不是进行所有递归检查的狂热追逐。例如,如果对象是User,则可以比较它们的emailAddress字段。

它仍然不是一个完美的解决方案,但是解决方案2的好处是:

  1. 这是可以预见的,并且崩溃的可能性较小。
  2. 您正在推动平等的“定义”,而不是依靠对象的原始形式和形状以及其原型和嵌套属性。

3)使用equal函数的库版本

如果需要生产级别的质量,并且不能更改系统的设计,则很好。

例如_.equal of lodash,已经在coolaj86's answerTony Harvey's answer或Node的by Rafael Xavier中提到的Angular或Ember中。

  • 优点:这是其他人所做的
  • 缺点::外部依赖关系,这可能使您付出额外的内存/ CPU /安全问题,甚至花一点时间。此外,仍然可能会错过某些边缘情况(例如,是否应该将具有相同ownProperties但原型父代不同的两个对象视为相同)。最后,可能是无意带-以此来解决潜在的设计问题;只是说!

我父亲的比喻

这就像向中介公司付款,根据他的电话,姓名,地址等找到我的亲生父亲。

这将花费更多,并且可能比我进行背景检查更准确,但是并不能涵盖像我父亲是移民/庇护而他的生日不详的情况下


4)在对象中使用IDentifier

如果您[仍然]可以更改系统(正在处理的对象)的设计并且希望代码持续很长时间,那就很好。

它并非在所有情况下都适用,并且可能不是很出色。但是,如果可以的话,这是一个非常可靠的解决方案。

解决方案是,系统中的每个object都将具有唯一标识符以及所有其他属性。标识符的唯一性将在生成时得到保证。在比较两个对象时,将使用此ID(也称为UUID / GUID-Globally/Universally Unique Identifier)。即,当且仅当这些ID相等时,它们才相等。

ID可以是简单的auto_incremental数字,也可以是通过a library(建议)或a piece of code生成的字符串。您需要做的就是确保它始终是唯一的,如果是auto_incremental,它可以是内置的;如果是UUID,则可以检查所有现有值(例如MySQL的UNIQUE列)属性)或简单地(如果来自库)依赖于发生碰撞的可能性极低。

请注意,您还需要始终将ID与对象一起存储(以确保其唯一性),并且实时计算它可能不是最佳方法。

  • 优点:可靠,高效,不肮脏,现代。
  • 缺点:需要更多空间。可能需要重新设计系统。

我父亲的比喻

这就像我父亲的社会安全号码是911-345-9283,所以拥有此SSN的任何人都是我的父亲,任何声称是我父亲的人都必须具有此SSN。


结论

出于个人的准确性和可靠性,我个人更喜欢解决方案4(ID)。如果不可能,我将使用#2.1进行可预测性,然后使用#3。如果不可能,请#2,最后是#1。

答案 18 :(得分:3)

下面是一个简短的实现,它使用 JSON.stringify 但按照 @Jor 建议的 here 对键进行排序。

一些测试来自@EbrahimByagowi here 的回答。

当然,通过使用 JSON.stringify,解决方案仅限于 JSON 可序列化类型(字符串、数字、JSON 对象、数组、布尔值、null)。不支持 DateFunction 等对象。

function objectEquals(obj1, obj2) {
  const JSONstringifyOrder = obj => {
    const keys = {};
    JSON.stringify(obj, (key, value) => {
      keys[key] = null;
      return value;
    });
    return JSON.stringify(obj, Object.keys(keys).sort());
  };
  return JSONstringifyOrder(obj1) === JSONstringifyOrder(obj2);
}

///////////////////////////////////////////////////////////////
/// 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("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}}));

答案 19 :(得分:3)

只是想利用一些es6功能贡献我的对象版本比较。它没有考虑订单。在将所有if / else&s转换为三元之后,我带来了以下内容:

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;

        }
    )
}

答案 20 :(得分:3)

如果您要比较JSON对象,可以使用https://github.com/mirek/node-rus-diff

npm install rus-diff

用法:

a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}

var rusDiff = require('rus-diff').rusDiff

console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }

如果两个对象不同,则返回与MongoDB兼容的{$rename:{...}, $unset:{...}, $set:{...}}对象。

答案 21 :(得分:3)

我遇到了同样的问题,并决定编写自己的解决方案。但是因为我想比较Arrays和Objects,反之亦然,我制作了一个通用的解决方案。我决定将这些函数添加到原型中,但可以轻松地将它们重写为独立函数。这是代码:

Array.prototype.equals = Object.prototype.equals = function(b) {
    var ar = JSON.parse(JSON.stringify(b));
    var err = false;
    for(var key in this) {
        if(this.hasOwnProperty(key)) {
            var found = ar.find(this[key]);
            if(found > -1) {
                if(Object.prototype.toString.call(ar) === "[object Object]") {
                    delete ar[Object.keys(ar)[found]];
                }
                else {
                    ar.splice(found, 1);
                }
            }
            else {
                err = true;
                break;
            }
        }
    };
    if(Object.keys(ar).length > 0 || err) {
        return false;
    }
    return true;
}

Array.prototype.find = Object.prototype.find = function(v) {
    var f = -1;
    for(var i in this) {
        if(this.hasOwnProperty(i)) {
            if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
                if(this[i].equals(v)) {
                    f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
                }
            }
            else if(this[i] === v) {
                f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
            }
        }
    }
    return f;
}

该算法分为两部分; equals函数本身和一个函数,用于查找数组/对象中属性的数字索引。只需要查找函数,因为indexof只查找数字和字符串而没有对象。

可以这样称呼它:

({a: 1, b: "h"}).equals({a: 1, b: "h"});

该函数返回true或false,在本例中为true。 算法允许比较非常复杂的对象:

({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})

上面的示例将返回true,即使属性具有不同的顺序。需要注意的一个小细节:此代码还检查相同类型的两个变量,因此“3”与3不同。

答案 22 :(得分:3)

需要比发布的更通用的对象比较功能,我做了以下工作。批评赞赏......

Object.prototype.equals = function(iObj) {
  if (this.constructor !== iObj.constructor)
    return false;
  var aMemberCount = 0;
  for (var a in this) {
    if (!this.hasOwnProperty(a))
      continue;
    if (typeof this[a] === 'object' && typeof iObj[a] === 'object' ? !this[a].equals(iObj[a]) : this[a] !== iObj[a])
      return false;
    ++aMemberCount;
  }
  for (var a in iObj)
    if (iObj.hasOwnProperty(a))
      --aMemberCount;
  return aMemberCount ? false : true;
}

答案 23 :(得分:3)

我建议不要使用散列或序列化(如JSON解决方案所示)。如果您需要测试两个对象是否相等,那么您需要定义equals的含义。可能是两个对象中的所有数据成员都匹配,或者可能是内存位置必须匹配(意味着两个变量都引用内存中的同一个对象),或者每个对象中只有一个数据成员必须匹配。

最近,我开发了一个对象,每次创建实例时,构造函数都会创建一个新的id(从1开始并递增1)。该对象有一个isEqual函数,用于将该id值与另一个对象的id值进行比较,如果匹配则返回true。

在这种情况下,我将“相等”定义为id值匹配。鉴于每个实例都具有唯一ID,这可用于强制匹配对象也占据相同内存位置的想法。虽然没有必要。

答案 24 :(得分:2)

我知道这有点旧,但我想添加一个解决方案,我想出了这个问题。 我有一个对象,我想知道它的数据何时发生变化。 &#34;类似于Object.observe&#34;我做的是:

function checkObjects(obj,obj2){
   var values = [];
   var keys = [];
   keys = Object.keys(obj);
   keys.forEach(function(key){
      values.push(key);
   });
   var values2 = [];
   var keys2 = [];
   keys2 = Object.keys(obj2);
   keys2.forEach(function(key){
      values2.push(key);
   });
   return (values == values2 && keys == keys2)
}

这里可以复制并创建另一组数组来比较值和键。 它非常简单,因为它们现在是数组,如果对象具有不同的大小,它将返回false。

答案 25 :(得分:2)

这是stringify技巧的一个版本,它可以减少输入,并且可以在很多情况下进行简单的JSON数据比较。

<?php
function a(&$a, &$b) {  
     $a =& $b;  
}
$a = 1;
$b = 2;
a($a, $b);
$b = 3;
print $a;
?>

答案 26 :(得分:2)

假设对象中属性的顺序没有改变。

JSON.stringify()适用于深层和非深层两种类型的对象,不太确定性能方面:

&#13;
&#13;
    $count_quot = $this->QuotationGeneration->find('count');
    $count_quot = $count_quot + 1;

    $number = str_pad($count_quot, 4, '0', STR_PAD_LEFT);

    $quotation_number = 'AP-00-'.$number;

    $this->set('quotation_number',$quotation_number);
&#13;
&#13;
&#13;

答案 27 :(得分:2)

我看到了意粉代码的答案。 不使用任何第三方库,这很容易。

首先通过键的键名对两个对象进行排序。

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)

答案 28 :(得分:2)

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}));

答案 29 :(得分:2)

对于那些使用NodeJS的人来说,本机Util库上有一个名为$('#loader .spinner').remove();的便捷方法可以实现此目的。

$('#loader').remove();

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

答案 30 :(得分:2)

从我的个人图书馆退出,我多次用于我的工作。以下函数是一个宽泛的递归深度相等,不检查

  • 班级平等
  • 继承值
  • 值严格相等

我主要用它来检查我是否得到了针对各种API实现的平等回复。可能发生实现差异(如字符串与数字)和其他空值。

它的实现非常简单和简短(如果所有注释都被删除)

&#13;
&#13;
/** Recursively check if both objects are equal in value
***
*** This function is designed to use multiple methods from most probable 
*** (and in most cases) valid, to the more regid and complex method.
***
*** One of the main principles behind the various check is that while
*** some of the simpler checks such as == or JSON may cause false negatives,
*** they do not cause false positives. As such they can be safely run first.
***
*** # !Important Note:
*** as this function is designed for simplified deep equal checks it is not designed
*** for the following
***
*** - Class equality, (ClassA().a = 1) maybe valid to (ClassB().b = 1)
*** - Inherited values, this actually ignores them
*** - Values being strictly equal, "1" is equal to 1 (see the basic equality check on this)
*** - Performance across all cases. This is designed for high performance on the
***   most probable cases of == / JSON equality. Consider bench testing, if you have
***   more 'complex' requirments
***
*** @param  objA : First object to compare
*** @param  objB : 2nd object to compare
*** @param  .... : Any other objects to compare
***
*** @returns true if all equals, or false if invalid
***
*** @license Copyright by eugene@picoded.com, 2012.
***          Licensed under the MIT license: http://opensource.org/licenses/MIT
**/
function simpleRecusiveDeepEqual(objA, objB) {
	// Multiple comparision check
	//--------------------------------------------
	var args = Array.prototype.slice.call(arguments);
	if(args.length > 2) {
		for(var a=1; a<args.length; ++a) {
			if(!simpleRecusiveDeepEqual(args[a-1], args[a])) {
				return false;
			}
		}
		return true;
	} else if(args.length < 2) {
		throw "simpleRecusiveDeepEqual, requires atleast 2 arguments";
	}
	
	// basic equality check,
	//--------------------------------------------
	// if this succed the 2 basic values is equal,
	// such as numbers and string.
	//
	// or its actually the same object pointer. Bam
	//
	// Note that if string and number strictly equal is required
	// change the equality from ==, to ===
	//
	if(objA == objB) {
		return true;
	}
	
	// If a value is a bsic type, and failed above. This fails
	var basicTypes = ["boolean", "number", "string"];
	if( basicTypes.indexOf(typeof objA) >= 0 || basicTypes.indexOf(typeof objB) >= 0 ) {
		return false;
	}
	
	// JSON equality check,
	//--------------------------------------------
	// this can fail, if the JSON stringify the objects in the wrong order
	// for example the following may fail, due to different string order:
	//
	// JSON.stringify( {a:1, b:2} ) == JSON.stringify( {b:2, a:1} )
	//
	if(JSON.stringify(objA) == JSON.stringify(objB)) {
		return true;
	}
	
	// Array equality check
	//--------------------------------------------
	// This is performed prior to iteration check,
	// Without this check the following would have been considered valid
	//
	// simpleRecusiveDeepEqual( { 0:1963 }, [1963] );
	//
	// Note that u may remove this segment if this is what is intended
	//
	if( Array.isArray(objA) ) {
		//objA is array, objB is not an array
		if( !Array.isArray(objB) ) {
			return false;
		}
	} else if( Array.isArray(objB) ) {
		//objA is not array, objB is an array
		return false;
	}
	
	// Nested values iteration
	//--------------------------------------------
	// Scan and iterate all the nested values, and check for non equal values recusively
	//
	// Note that this does not check against null equality, remove the various "!= null"
	// if this is required
	
	var i; //reuse var to iterate
	
	// Check objA values against objB
	for (i in objA) {
		//Protect against inherited properties
		if(objA.hasOwnProperty(i)) {
			if(objB.hasOwnProperty(i)) {
				// Check if deep equal is valid
				if(!simpleRecusiveDeepEqual( objA[i], objB[i] )) {
					return false;
				}
			} else if(objA[i] != null) {
				//ignore null values in objA, that objB does not have
				//else fails
				return false;
			}
		}
	}
	
	// Check if objB has additional values, that objA do not, fail if so
	for (i in objB) {
		if(objB.hasOwnProperty(i)) {
			if(objB[i] != null && !objA.hasOwnProperty(i)) {
				//ignore null values in objB, that objA does not have
				//else fails
				return false;
			}
		}
	}
	
	// End of all checks
	//--------------------------------------------
	// By reaching here, all iteration scans have been done.
	// and should have returned false if it failed
	return true;
}

// Sanity checking of simpleRecusiveDeepEqual
(function() {
	if(
		// Basic checks
		!simpleRecusiveDeepEqual({}, {}) ||
		!simpleRecusiveDeepEqual([], []) ||
		!simpleRecusiveDeepEqual(['a'], ['a']) ||
		// Not strict checks
		!simpleRecusiveDeepEqual("1", 1) ||
		// Multiple objects check
		!simpleRecusiveDeepEqual( { a:[1,2] }, { a:[1,2] }, { a:[1,2] } ) ||
		// Ensure distinction between array and object (the following should fail)
		simpleRecusiveDeepEqual( [1963], { 0:1963 } ) ||
		// Null strict checks
		simpleRecusiveDeepEqual( 0, null ) ||
		simpleRecusiveDeepEqual( "", null ) ||
		// Last "false" exists to make the various check above easy to comment in/out
		false
	) {
		alert("FATAL ERROR: simpleRecusiveDeepEqual failed basic checks");
	} else { 
		//added this last line, for SO snippet alert on success
		alert("simpleRecusiveDeepEqual: Passed all checks, Yays!");
	}
})();
&#13;
&#13;
&#13;

答案 31 :(得分:2)

如果两个对象的所有属性具有相同的值,并且对所有嵌套对象和数组都是递归的,则认为这两个对象是相同的。我还认为以下两个对象是相同的:

var a = {p1: 1};
var b = {p1: 1, p2: undefined};

类似地,数组可以具有“缺失”元素和未定义元素。我会同样对待那些:

var c = [1, 2];
var d = [1, 2, undefined];

实现此等式定义的函数:

function isEqual(a, b) {
    if (a === b) {
        return true;
    }

    if (generalType(a) != generalType(b)) {
        return false;
    }

    if (a == b) {
        return true;
    }

    if (typeof a != 'object') {
        return false;
    }

    // null != {}
    if (a instanceof Object != b instanceof Object) {
        return false;
    }

    if (a instanceof Date || b instanceof Date) {
        if (a instanceof Date != b instanceof Date ||
            a.getTime() != b.getTime()) {
            return false;
        }
    }

    var allKeys = [].concat(keys(a), keys(b));
    uniqueArray(allKeys);

    for (var i = 0; i < allKeys.length; i++) {
        var prop = allKeys[i];
        if (!isEqual(a[prop], b[prop])) {
            return false;
        }
    }
    return true;
}

Source code(包括辅助函数,generalType和uniqueArray): Unit TestTest Runner here

答案 32 :(得分:2)

这里是一个使用 ES6+ 的解决方案

.stories {
  height: 100vh;
  background-image: linear-gradient(black, #1a1a1a);
  padding: 0;
  margin: 0;
  display: flex;
}

答案 33 :(得分:2)

这是上述所有内容的补充,而不是替代品。如果你需要快速浅比较对象而不需要检查额外的递归情况。这是一个镜头。

比较:1)自有属性的数量相等,2)键名相等,3)如果bCompareValues == true,相应属性值的等价及其类型(三重相等)

var shallowCompareObjects = function(o1, o2, bCompareValues) {
    var s, 
        n1 = 0,
        n2 = 0,
        b  = true;

    for (s in o1) { n1 ++; }
    for (s in o2) { 
        if (!o1.hasOwnProperty(s)) {
            b = false;
            break;
        }
        if (bCompareValues && o1[s] !== o2[s]) {
            b = false;
            break;
        }
        n2 ++;
    }
    return b && n1 == n2;
}

答案 34 :(得分:2)

为了比较简单键/值对对象实例的键,我使用:

function compareKeys(r1, r2) {
    var nloops = 0, score = 0;
    for(k1 in r1) {
        for(k2 in r2) {
            nloops++;
            if(k1 == k2)
                score++; 
        }
    }
    return nloops == (score * score);
};

比较密钥后,只需一个简单的额外for..in循环即可。

复杂度为O(N * N),N为键数。

我希望/猜测我​​定义的对象不会超过1000个属性......

答案 35 :(得分:2)

我正在使用此函数做出以下假设:

  1. 您可以控制要比较的对象,并且只有原始值(即不是嵌套对象,函数等)。
  2. 您的浏览器支持Object.keys
  3. 这应被视为一种简单策略的证明。

    /**
     * Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.)
     * @param {Object} object1
     * @param {Object} object2
     * @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}).
     * @returns {Boolean}
     */
    function isEqual( object1, object2, order_matters ) {
        var keys1 = Object.keys(object1),
            keys2 = Object.keys(object2),
            i, key;
    
        // Test 1: Same number of elements
        if( keys1.length != keys2.length ) {
            return false;
        }
    
        // If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true.
        // keys1 = Object.keys({a:2, b:1}) = ["a","b"];
        // keys2 = Object.keys({b:1, a:2}) = ["b","a"];
        // This is why we are sorting keys1 and keys2.
        if( !order_matters ) {
            keys1.sort();
            keys2.sort();
        }
    
        // Test 2: Same keys
        for( i = 0; i < keys1.length; i++ ) {
            if( keys1[i] != keys2[i] ) {
                return false;
            }
        }
    
        // Test 3: Values
        for( i = 0; i < keys1.length; i++ ) {
            key = keys1[i];
            if( object1[key] != object2[key] ) {
                return false;
            }
        }
    
        return true;
    }
    

答案 36 :(得分:1)

我不是Javascript专家,但这是一个简单的尝试来解决它。我检查了三件事:

  1. object还是null,因为typeof nullobject
  2. 如果两个对象的属性数相同?如果不是他们不平等。
  3. 循环遍历一个属性并检查相应属性是否在第二个对象中具有相同的值。
  4. function deepEqual (first, second) {
      // Not equal if either is not an object or is null.
      if (!isObject(first) || !isObject(second) ) return false;
    
      // If properties count is different
      if (keys(first).length != keys(second).length) return false;
    
      // Return false if any property value is different.
      for(prop in first){
        if (first[prop] != second[prop]) return false;
      }
      return true;
    }
    
    // Checks if argument is an object and is not null
    function isObject(obj) {
      return (typeof obj === "object" && obj != null);
    }
    
    // returns arrays of object keys
    function keys (obj) {
      result = [];
      for(var key in obj){
        result.push(key);
      }
      return result;
    }
    
    // Some test code
    obj1 = {
      name: 'Singh',
      age: 20
    }
    
    obj2 = {
      age: 20,
      name: 'Singh'
    }
    
    obj3 = {
      name: 'Kaur',
      age: 19
    }
    
    console.log(deepEqual(obj1, obj2));
    console.log(deepEqual(obj1, obj3));

答案 37 :(得分:1)

这是一个简单的Javascript函数,用于比较具有简单键值对的两个对象。该函数将返回一个字符串数组,其中每个字符串都是两个对象之间不等式的路径。

function compare(a,b) {
    var paths = [];
    [...new Set(Object.keys(a).concat(Object.keys(b)))].forEach(key=>{
        if(typeof a[key] === 'object' && typeof b[key] === 'object') {
            var results = compare(a[key], b[key]);
            if(JSON.stringify(results)!=='[]') {
                paths.push(...results.map(result=>key.concat("=>"+result)));
            }
        }
        else if (a[key]!==b[key]) {
            paths.push(key);
        }
    })
    return paths;
}

如果您只想比较两个对象而不知道不等式的路径,则可以按照以下步骤进行操作:

if(JSON.stringify(compare(object1, object2))==='[]') {
   // the two objects are equal
} else {
   // the two objects are not equal
}

答案 38 :(得分:1)

取决于平等意味着什么。因此,作为类的开发者,您可以自己定义它们的相等性。

有时会使用一种情况,如果两个实例指向内存中的相同位置,则认为它们是“相等的”,但这并不总是您想要的。例如,如果我有一个Person类,如果它们具有相同的姓氏,名字和社会安全号码(即使它们指向内存中的不同位置),我可能想要将两个Person对象视为“相等”。

另一方面,如果每个成员的价值相同,我们不能简单地说两个对象是相同的,因为有时你不想这样做。换句话说,对于每个类,由类开发人员来定义构成对象“身份”的成员并开发适当的相等运算符(通过重载==运算符或Equals方法)。

如果两个对象具有相同的哈希值,那么两个对象是相等的。但是,您必须想知道如何为每个实例计算哈希值。回到上面的Person示例,如果通过查看First Name,Last Name和Social Security Number字段的值来计算哈希,我们可以使用此系统。最重要的是,我们依赖于散列方法的质量(这本身就是一个很大的主题,但是说不是所有的散列都是平等的,而且糟糕的散列方法可以导致更多< / em> collisions,在这种情况下会返回错误匹配)。

答案 39 :(得分:1)

取决于。如果对象中键的顺序不重要,那么我就不需要知道该对象的原型。使用“总是做”。

$('label').filter(function() 
(
{return $.trim($(this).text()) === "Text A:";}).closest('div').addClass('textAclass');
{return $.trim($(this).text()) === "Text B:";}).closest('div').addClass('textBclass');
{return $.trim($(this).text()) === "Text C:";}).closest('div').addClass('textCclass');
);

答案 40 :(得分:1)

对于这个有一个非常简单的修复,当你比较两个对象时,你所要做的就是JSON.stringify()。

答案 41 :(得分:1)

const obj = {
  name: "Carl",
  age: 15
}
const obj2 = {
  name: "Carl",
  age: 15,
}


const compareObj = (objects) => {
  const res =  objects.map((item) => {
    return Object.entries(item).flat().join()
  })
  return res.every((a) => {
    return a === res[0]
  })
}

console.log(compareObj([obj,obj2]))

答案 42 :(得分:1)

  1. 对对象(字典)进行排序
  2. 比较JSON字符串

    function areTwoDictsEqual(dictA, dictB) {
        function sortDict(dict) {
            var keys = Object.keys(dict);
            keys.sort();
    
            var newDict = {};
            for (var i=0; i<keys.length; i++) {
                var key = keys[i];
                var value = dict[key];
                newDict[key] = value;
            } 
            return newDict;
        }
    
        return JSON.stringify(sortDict(dictA)) == JSON.stringify(sortDict(dictB));
    }
    

答案 43 :(得分:1)

经过大量搜索,我找到了以下可行的解决方案

function isEquivalent(a, b) {
   // Create arrays of property names
   var aProps = Object.getOwnPropertyNames(a);
   var bProps = Object.getOwnPropertyNames(b);

  // If number of properties is different, objects are not equivalent
  if (aProps.length != bProps.length) {
     return false;
  }

  for (var i = 0; i < aProps.length; i++) {
     var propName = aProps[i];

    // If values of same property are not equal, objects are not equivalent
     if (a[propName] !== b[propName]) {
         return false;
     }
  }

// If we made it this far, objects are considered equivalent
return true; }

有关更多信息:Object Equality in JavaScript

答案 44 :(得分:1)

这是检查对象&#34;价值平等的一种非常基本的方法&#34;。

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

function isEquivalent(a, b) {
    // Create arrays of property names

    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different, objects are not equivalent

    if (aProps.length != bProps.length) {
        return false;
    }

    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];

        // If values of same property are not equal, objects are not equivalent
        if (a[propName] !== b[propName]) {
           return false;
        }
    }

    // If we made it this far, objects are considered equivalent
    return true;
}

// Outputs: true
console.log(isEquivalent(john, bobby));

Demo - JSFiddle

如您所见,检查对象&#39; &#34;价值平等&#34;我们基本上必须迭代对象中的每个属性以查看它们是否相等。虽然这个简单的实现适用于我们的示例,但是有很多情况它无法处理。例如:

  • 如果其中一个属性值本身就是一个对象怎么办?
  • 如果其中一个属性值是NaN(唯一的值),该怎么办? JavaScript本身不相同?)
  • 如果a具有未定义值的属性,而b不具有该属性,该怎么办? 这个属性(因此评估为未定义?)

用于检查对象的强大方法&#39; &#34;价值平等&#34;最好依靠经过充分测试的库来涵盖Underscore等各种边缘情况。

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

// Outputs: true
console.log(_.isEqual(john, bobby));

Demo - JSFiddle

答案 45 :(得分:1)

如何确定部分对象(Partial )等于打字稿中的原始对象(T)。

function compareTwoObjects<T>(original: T, partial: Partial<T>): boolean {
  return !Object.keys(partial).some((key) => partial[key] !== original[key]);
}

P.S。最初,我打算创建一个带有答案的新问题。但是这样的问题已经存在并标记为重复。

答案 46 :(得分:1)

我只是编写此方法只是为了确保以清晰的方式比较数组和对象。

这也可以解决问题! :)

build

答案 47 :(得分:0)

const one={name:'mohit' , age:30};
//const two ={name:'mohit',age:30};
const two ={age:30,name:'mohit'};

function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);



// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
    return false;
}

for (var i = 0; i < aProps.length; i++) {
    var propName = aProps[i];

    // If values of same property are not equal,
    // objects are not equivalent
    if (a[propName] !== b[propName]) {
        return false;
    }
}

// If we made it this far, objects
// are considered equivalent
return true;
}

console.log(isEquivalent(one,two))

答案 48 :(得分:0)

如果你真的想比较并返回两个对象的差异。 你可以使用这个包:https://www.npmjs.com/package/deep-diff

或者直接使用这个包使用的代码

https://github.com/flitbit/diff/blob/master/index.js

只是不要将其转换为字符串进行比较。

答案 49 :(得分:0)

尽管已经有很多关于这个问题的答案。我的尝试只是提供另一种实现方法:

const primitveDataTypes = ['number', 'boolean', 'string', 'undefined'];
const isDateOrRegExp = (value) => value instanceof Date || value instanceof RegExp;
const compare = (first, second) => {
    let agg = true;
    if(typeof first === typeof second && primitveDataTypes.indexOf(typeof first) !== -1 && first !== second){
        agg =  false;
    }
    // adding support for Date and RegExp.
    else if(isDateOrRegExp(first) || isDateOrRegExp(second)){
        if(first.toString() !== second.toString()){
            agg = false;
        }
    }
    else {
        if(Array.isArray(first) && Array.isArray(second)){
        if(first.length === second.length){
             for(let i = 0; i < first.length; i++){
                if(typeof first[i] === 'object' && typeof second[i] === 'object'){
                    agg = compare(first[i], second[i]);
                }
                else if(first[i] !== second[i]){
                    agg = false;
                }
            }
        } else {
            agg = false;
        }
    } else {
        const firstKeys = Object.keys(first);
        const secondKeys = Object.keys(second);
        if(firstKeys.length !== secondKeys.length){
            agg = false;
        }
        for(let j = 0 ; j < firstKeys.length; j++){
            if(firstKeys[j] !== secondKeys[j]){
                agg = false;
            }
            if(first[firstKeys[j]] && second[secondKeys[j]] && typeof first[firstKeys[j]] === 'object' && typeof second[secondKeys[j]] === 'object'){
                agg = compare(first[firstKeys[j]], second[secondKeys[j]]);
             } 
             else if(first[firstKeys[j]] !== second[secondKeys[j]]){
                agg = false;
             } 
        }
    }
    }
    return agg;
}


console.log('result', compare({a: 1, b: { c: [4, {d:5}, {e:6}]}, r: null}, {a: 1, b: { c: [4, {d:5}, {e:6}]}, r: 'ffd'}));  //returns false.

答案 50 :(得分:0)

另一种选择是使用Ramda library中的equals

const c = {a: 1, b: 2};
const d = {b: 2, a: 1};
R.equals(c, d); //=> true

答案 51 :(得分:0)

尽管这个问题得到了充分的回答,但我还是遗漏了一种方法:toJSON 接口。

通常你想通过字符串化来与对象进行比较,因为这是最快的方法。但是由于属性的顺序,这种比较经常被认为是错误的。

const obj1 = {
  a: 1,
  b: 2,
  c: { 
    ca: 1,
    cb: 2
  }
}

const obj2 = {
  b: 2, // changed order with a
  a: 1,
  c: { 
    ca: 1,
    cb: 2
  }
}

JSON.stringify(obj1) === JSON.stringify(obj2) // false

显然对象被认为是不同的,因为属性 ab 的顺序不同。

为了解决这个问题,您可以实现 toJSON 接口,并定义一个确定性输出。

const obj1 = {
  a: 1,
  b: 2,
  c: { 
    ca: 1,
    cb: 2
  },
  toJSON() {
    return {
      a: this.a,
      b: this.b,
      c: { 
        ca: this.c.ca,
        cb: this.c.ca
      }
    }
  }
}

const obj2 = {
  b: 2,
  a: 1,
  c: { 
    ca: 1,
    cb: 2
  },
  toJSON() {
    return {
      a: this.a,
      b: this.b,
      c: { 
        ca: this.c.ca,
        cb: this.c.ca
      }
    }
  }
}

JSON.stringify(obj1) === JSON.stringify(obj2) // true

等等:obj1obj2 的字符串表示被认为是相同的。

提示

如果您无法直接生成对象,则可以简单地附加 toJSON 函数:

obj1.toJSON = function() {
  return {
    a: this.a,
    b: this.b,
    c: { 
      ca: this.c.ca,
      cb: this.c.ca
    }
  }
}

obj2.toJSON = function() {
  return {
    a: this.a,
    b: this.b,
    c: { 
      ca: this.c.ca,
      cb: this.c.ca
    }
  }
}

JSON.stringify(obj1) === JSON.stringify(obj2) // true

答案 52 :(得分:0)

在对象(没有方法)中,我们需要检查 nested ObjectsArraysprimitive types。对象可以有其他对象和数组(数组也可以包含其他对象和数组),因此我们可以使用如下递归函数:arrayEquals 检查数组是否相等,equals 检查对象是否相等:

function arrayEquals(a, b) {
    if (a.length != b.length) {
        return false;
    }
    for (let i = 0; i < a.length; i++) {
        if (a[i].constructor !== b[i].constructor) {
            return false;
        }

        if (a[i] instanceof Array && b[i] instanceof Array) {
            if (!arrayEquals(a, b)) {
                return false;
            }
        } else if (a[i] instanceof Object && b[i] instanceof Object) {
            if (!equals(a[i], b[i])) {
                return false;
            }
        } else if (a[i] !== b[i]) {
            return false;
        }
    }
    return true;
}

function equals(a, b) {
    for (let el in a) {
        if (b.hasOwnProperty(el)) {
            if (a[el].constructor !== b[el].constructor) {
                return false;
            }

            if (a[el] instanceof Array && b[el] instanceof Array) {
                if (!arrayEquals(a[el], b[el])) {
                    return false;
                }
            } else if (a[el] instanceof Object && b[el] instanceof Object) {
                if (!equals(a[el], b[el])) {
                    return false;
                }
            } else if (a[el] !== b[el]) {
                return false;
            }
        } else {
            return false;
        }
    }
    return true;
}

假设您有两个对象:

let a = {
    a: 1,
    b: { c: 1, d: "test" },
    c: 3,
    d: [{ a: [1, 2], e: 2 }, "test", { c: 3, q: 5 }],
};

let b = {
    a: 1,
    b: { c: 1, d: "test" },
    c: 3,
    d: [{ a: [1, 2], e: 2 }, "test", { c: 3, q: 5 }],
};

这里使用上面的 equals 函数,您可以像这样轻松比较其中两个对象:

if(equals(a, b)) {
    // do whatever you want
}

答案 53 :(得分:0)

这是一个经典的JavaScript问题!我创建了一种方法来检查深层对象是否相等,其功能是可以选择要从比较中忽略的属性。 参数是要比较的两个对象,另外还有一个可选的字符串化属性,可忽略相对路径。

function isObjectEqual( o1, o2, ignorePropsArr=[]) {
    // Deep Clone objects
    let _obj1 = JSON.parse(JSON.stringify(o1)),
        _obj2 = JSON.parse(JSON.stringify(o2));
    // Remove props to ignore
    ignorePropsArr.map( p => { 
        eval('_obj1.'+p+' = _obj2.'+p+' = "IGNORED"');
    });
    // compare as strings
    let s1 = JSON.stringify(_obj1),
        s2 = JSON.stringify(_obj2);
    // return [s1==s2,s1,s2];
    return s1==s2;
}

// Objects 0 and 1 are exact equals
obj0 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj1 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj2 = { price: 66544.12, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj3 = { price: 66544.13, RSIs: [0.000432334, 0.00046531], candles: {A: 541, B: 321, C: 4322}}
obj4 = { price: 66544.14, RSIs: [0.000432334, 0.00046530], candles: {A: 543, B: 321, C: 4322}}

isObjectEqual(obj0,obj1) // true
isObjectEqual(obj0,obj2) // false
isObjectEqual(obj0,obj2,['price']) // true
isObjectEqual(obj0,obj3,['price']) // false
isObjectEqual(obj0,obj3,['price','candles.A']) // true
isObjectEqual(obj0,obj4,['price','RSIs[1]'])   // true

答案 54 :(得分:0)

是的,另一个答案......

Object.prototype.equals = function (object) {
    if (this.constructor !== object.constructor) return false;
    if (Object.keys(this).length !== Object.keys(object).length) return false;
    var obk;
    for (obk in object) {
        if (this[obk] !== object[obk])
            return false;
    }
    return true;
}

var aaa = JSON.parse('{"name":"mike","tel":"1324356584"}');
var bbb = JSON.parse('{"tel":"1324356584","name":"mike"}');
var ccc = JSON.parse('{"name":"mike","tel":"584"}');
var ddd = JSON.parse('{"name":"mike","tel":"1324356584", "work":"nope"}');

$("#ab").text(aaa.equals(bbb));
$("#ba").text(bbb.equals(aaa));
$("#bc").text(bbb.equals(ccc));
$("#ad").text(aaa.equals(ddd));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
aaa equals bbb? <span id="ab"></span> <br/>
bbb equals aaa? <span id="ba"></span> <br/>
bbb equals ccc? <span id="bc"></span> <br/>
aaa equals ddd? <span id="ad"></span>

答案 55 :(得分:0)

我需要模拟jQuery POST请求,因此对我来说重要的是两个对象具有相同的属性集(在任一对象中都没有丢失),并且每个属性值都是“相等”(根据此定义) )。我不关心具有不匹配方法的对象。

以下是我将要使用的内容,它应该足以满足我的特定要求:

function PostRequest() {
    for (var i = 0; i < arguments.length; i += 2) {
        this[arguments[i]] = arguments[i+1];
    }

    var compare = function(u, v) {
        if (typeof(u) != typeof(v)) {
            return false;
        }

        var allkeys = {};
        for (var i in u) {
            allkeys[i] = 1;
        }
        for (var i in v) {
            allkeys[i] = 1;
        }
        for (var i in allkeys) {
            if (u.hasOwnProperty(i) != v.hasOwnProperty(i)) {
                if ((u.hasOwnProperty(i) && typeof(u[i]) == 'function') ||
                    (v.hasOwnProperty(i) && typeof(v[i]) == 'function')) {
                    continue;
                } else {
                    return false;
                }
            }
            if (typeof(u[i]) != typeof(v[i])) {
                return false;
            }
            if (typeof(u[i]) == 'object') {
                if (!compare(u[i], v[i])) {
                    return false;
                }
            } else {
                if (u[i] !== v[i]) {
                    return false;
                }
            }
        }

        return true;
    };

    this.equals = function(o) {
        return compare(this, o);
    };

    return this;
}

像这样使用:

foo = new PostRequest('text', 'hello', 'html', '<p>hello</p>');
foo.equals({ html: '<p>hello</p>', text: 'hello' });

答案 56 :(得分:0)

我编写了一个在Node.js上运行的小型库,以及名为compare.js的浏览器。它提供了通常的比较运算符,例如==,!=,&gt;,&gt; =,&lt;,&lt; =以及所有JavaScript数据类型的标识。

例如,您可以使用

cmp.eq(obj1, obj2);

这将检查是否相等(使用深度相等的方法)。否则,如果你这样做

cmp.id(obj1, obj2);

它将通过引用进行比较,从而检查身份。 你也可以使用&lt;和&gt;对象,即子集和超集。

compare.js被近700个单元测试覆盖,因此它应该没有太多错误; - )。

您可以在https://github.com/goloroden/compare.js免费找到它,它是根据MIT许可证开源的。

答案 57 :(得分:0)

快速“黑客”判断两个对象是否相似,就是使用他们的toString()方法。如果要检查对象A和B,请确保A和B具有有意义的toString()方法,并检查它们返回的字符串是否相同。

这不是灵丹妙药,但在适当的情况下它有时会很有用。

答案 58 :(得分:0)

function isEqual(obj1, obj2){
    type1 = typeof(obj1);
    type2 = typeof(obj2);
    if(type1===type2){
        switch (type1){
            case "object": return JSON.stringify(obj1)===JSON.stringify(obj2);
            case "function": return eval(obj1).toString()===eval(obj2).toString();
            default: return obj1==obj2;
        }
    }
    return false;
}//have not tried but should work.

答案 59 :(得分:0)

这是一个非常干净的CoffeeScript版本,你可以这样做:

Object::equals = (other) ->
  typeOf = Object::toString

  return false if typeOf.call(this) isnt typeOf.call(other)
  return `this == other` unless typeOf.call(other) is '[object Object]' or
                                typeOf.call(other) is '[object Array]'

  (return false unless this[key].equals other[key]) for key, value of this
  (return false if typeof this[key] is 'undefined') for key of other

  true

以下是测试:

  describe "equals", ->

    it "should consider two numbers to be equal", ->
      assert 5.equals(5)

    it "should consider two empty objects to be equal", ->
      assert {}.equals({})

    it "should consider two objects with one key to be equal", ->
      assert {a: "banana"}.equals {a: "banana"}

    it "should consider two objects with keys in different orders to be equal", ->
      assert {a: "banana", kendall: "garrus"}.equals {kendall: "garrus", a: "banana"}

    it "should consider two objects with nested objects to be equal", ->
      assert {a: {fruit: "banana"}}.equals {a: {fruit: "banana"}}

    it "should consider two objects with nested objects that are jumbled to be equal", ->
      assert {a: {a: "banana", kendall: "garrus"}}.equals {a: {kendall: "garrus", a: "banana"}}

    it "should consider two objects with arrays as values to be equal", ->
      assert {a: ["apple", "banana"]}.equals {a: ["apple", "banana"]}



    it "should not consider an object to be equal to null", ->
      assert !({a: "banana"}.equals null)

    it "should not consider two objects with different keys to be equal", ->
      assert !({a: "banana"}.equals {})

    it "should not consider two objects with different values to be equal", ->
      assert !({a: "banana"}.equals {a: "grapefruit"})

答案 60 :(得分:0)

以下某些解决方案在性能,功能和风格方面存在问题......它们没有经过充分考虑,其中一些解决方案因不同情况而失败。我试图在我自己的解决方案中解决这个问题,我非常感谢您的反馈:

http://stamat.wordpress.com/javascript-object-comparison/

//Returns the object's class, Array, Date, RegExp, Object are of interest to us
var getClass = function(val) {
    return Object.prototype.toString.call(val)
        .match(/^\[object\s(.*)\]$/)[1];
};

//Defines the type of the value, extended typeof
var whatis = function(val) {

    if (val === undefined)
        return 'undefined';
    if (val === null)
        return 'null';

    var type = typeof val;

    if (type === 'object')
        type = getClass(val).toLowerCase();

    if (type === 'number') {
        if (val.toString().indexOf('.') > 0)
            return 'float';
        else
        return 'integer';
    }

    return type;
   };

var compareObjects = function(a, b) {
    if (a === b)
        return true;
    for (var i in a) {
        if (b.hasOwnProperty(i)) {
            if (!equal(a[i],b[i])) return false;
        } else {
            return false;
        }
    }

    for (var i in b) {
        if (!a.hasOwnProperty(i)) {
            return false;
        }
    }
    return true;
};

var compareArrays = function(a, b) {
    if (a === b)
        return true;
    if (a.length !== b.length)
        return false;
    for (var i = 0; i < a.length; i++){
        if(!equal(a[i], b[i])) return false;
    };
    return true;
};

var _equal = {};
_equal.array = compareArrays;
_equal.object = compareObjects;
_equal.date = function(a, b) {
    return a.getTime() === b.getTime();
};
_equal.regexp = function(a, b) {
    return a.toString() === b.toString();
};
//  uncoment to support function as string compare
//  _equal.fucntion =  _equal.regexp;



/*
 * Are two values equal, deep compare for objects and arrays.
 * @param a {any}
 * @param b {any}
 * @return {boolean} Are equal?
 */
var equal = function(a, b) {
    if (a !== b) {
        var atype = whatis(a), btype = whatis(b);

        if (atype === btype)
            return _equal.hasOwnProperty(atype) ? _equal[atype](a, b) : a==b;

        return false;
    }

    return true;
};

答案 61 :(得分:0)

对象相等性检查:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

上述测试也适用于对象数组,在这种情况下使用http://www.w3schools.com/jsref/jsref_sort.asp中记录的排序函数

对于具有平面JSON模式的小数组,可能就足够了。

答案 62 :(得分:0)

当然,虽然我们正在努力,但我会自己重新发明轮子(我对所使用的辐条和材料的数量感到自豪):

////////////////////////////////////////////////////////////////////////////////

var equals = function ( objectA, objectB ) {
    var result = false,
        keysA,
        keysB;

    // Check if they are pointing at the same variable. If they are, no need to test further.
    if ( objectA === objectB ) {
        return true;
    }

    // Check if they are the same type. If they are not, no need to test further.
    if ( typeof objectA !== typeof objectB ) {
        return false;
    }

    // Check what kind of variables they are to see what sort of comparison we should make.
    if ( typeof objectA === "object" ) {
        // Check if they have the same constructor, so that we are comparing apples with apples.
        if ( objectA.constructor === objectA.constructor ) {
            // If we are working with Arrays...
            if ( objectA instanceof Array ) {
                // Check the arrays are the same length. If not, they cannot be the same.
                if ( objectA.length === objectB.length ) {
                    // Compare each element. They must be identical. If not, the comparison stops immediately and returns false.
                    return objectA.every(
                        function ( element, i ) {
                            return equals( element, objectB[ i ] );
                        }
                    );
                }
                // They are not the same length, and so are not identical.
                else {
                    return false;
                }
            }
            // If we are working with RegExps...
            else if ( objectA instanceof RegExp ) {
                // Return the results of a string comparison of the expression.
                return ( objectA.toString() === objectB.toString() );
            }
            // Else we are working with other types of objects...
            else {
                // Get the keys as arrays from both objects. This uses Object.keys, so no old browsers here.
                keysA = Object.keys( objectA );

                keysB = Object.keys( objectB );

                // Check the key arrays are the same length. If not, they cannot be the same.
                if ( keysA.length === keysB.length ) {
                    // Compare each property. They must be identical. If not, the comparison stops immediately and returns false.
                    return keysA.every(
                        function ( element ) {
                            return equals( objectA[ element ], objectB[ element ] );
                        }
                    );
                }
                // They do not have the same number of keys, and so are not identical.
                else {
                    return false;
                }
            }
        }
        // They don't have the same constructor.
        else {
            return false;
        }
    }
    // If they are both functions, let us do a string comparison.
    else if ( typeof objectA === "function" ) {
        return ( objectA.toString() === objectB.toString() );
    }
    // If a simple variable type, compare directly without coercion.
    else {
        return ( objectA === objectB );
    }

    // Return a default if nothing has already been returned.
    return result;
};

////////////////////////////////////////////////////////////////////////////////

尽快返回false,但当然对于差异深度嵌套的大型对象,它可能效果较差。在我自己的场景中,良好的嵌套数组处理非常重要。

希望它可以帮助需要这种轮子的人。

答案 63 :(得分:0)

这可以接受吗?

deepEqual = (x, y) => {
 let areEqual = false;
 const Obj = Object.keys(x);
 const keysSize = Obj.length;
 let counter = 0;
 Obj.forEach(key => {
  if (y[key] === x[key]) {
    counter += 1;
  }
 });
 if (counter === keysSize) areEqual = true;
 return areEqual;
};

答案 64 :(得分:0)

我有一个更短的功能,将深入到所有子对象或数组。它与JSON.stringify(obj1) === JSON.stringify(obj2)一样有效,但如果订单不相同(as mentioned here),则JSON.stringify将无效。

var obj1 = { a : 1, b : 2 };
var obj2 = { b : 2, a : 1 };

console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false

如果你想用不相等的值做某事,这个函数也是一个好的开始。

&#13;
&#13;
function arr_or_obj(v)
{ return !!v && (v.constructor === Object || v.constructor === Array); }

function deep_equal(v1, v2)
{
    if (arr_or_obj(v1) && arr_or_obj(v2) && v1.constructor === v2.constructor)
    {
        if (Object.keys(v1).length === Object.keys(v2).length) // check the length
        for (var i in v1)
        {
            if (!deep_equal(v1[i], v2[i]))
            { return false; }
        }
        else
        { return false; }
    }
    else if (v1 !== v2)
    { return false; }

    return true;
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

var obj1 = [
    {
        hat : {
            cap : ['something', null ],
            helmet : [ 'triple eight', 'pro-tec' ]
        },
        shoes : [ 'loafer', 'penny' ]
    },
    {
        beers : [ 'budweiser', 'busch' ],
        wines : [ 'barefoot', 'yellow tail' ]
    }
];

var obj2 = [
    {
        shoes : [ 'loafer', 'penny' ], // same even if the order is different
        hat : {
            cap : ['something', null ],
            helmet : [ 'triple eight', 'pro-tec' ]
        }
    },
    {
        beers : [ 'budweiser', 'busch' ],
        wines : [ 'barefoot', 'yellow tail' ]
    }
];

console.log(deep_equal(obj1, obj2)); // true
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false
console.log(deep_equal([], [])); // true
console.log(deep_equal({}, {})); // true
console.log(deep_equal([], {})); // false
&#13;
&#13;
&#13;

如果您想添加对FunctionDateRegExp的支持,可以在deep_equal(未经测试)的开头添加:

if ((typeof obj1 === 'function' && typeof obj2 === 'function') ||
(obj1 instanceof Date && obj2 instanceof Date) ||
(obj1 instanceof RegExp && obj2 instanceof RegExp))
{
    obj1 = obj1.toString();
    obj2 = obj2.toString();
}

答案 65 :(得分:0)

我的版本,其中包含找到差异的链条,以及区别的是什么。

function DeepObjectCompare(O1, O2)
{
    try {
        DOC_Val(O1, O2, ['O1->O2', O1, O2]);
        return DOC_Val(O2, O1, ['O2->O1', O1, O2]);
    } catch(e) {
        console.log(e.Chain);
        throw(e);
    }
}
function DOC_Error(Reason, Chain, Val1, Val2)
{
    this.Reason=Reason;
    this.Chain=Chain;
    this.Val1=Val1;
    this.Val2=Val2;
}

function DOC_Val(Val1, Val2, Chain)
{
    function DoThrow(Reason, NewChain) { throw(new DOC_Error(Reason, NewChain!==undefined ? NewChain : Chain, Val1, Val2)); }

    if(typeof(Val1)!==typeof(Val2))
        return DoThrow('Type Mismatch');
    if(Val1===null || Val1===undefined)
        return Val1!==Val2 ? DoThrow('Null/undefined mismatch') : true;
    if(Val1.constructor!==Val2.constructor)
        return DoThrow('Constructor mismatch');
    switch(typeof(Val1))
    {
        case 'object':
            for(var m in Val1)
            {
                if(!Val1.hasOwnProperty(m))
                    continue;
                var CurChain=Chain.concat([m]);
                if(!Val2.hasOwnProperty(m))
                    return DoThrow('Val2 missing property', CurChain);
                DOC_Val(Val1[m], Val2[m], CurChain);
            }
            return true;
        case 'number':
            if(Number.isNaN(Val1))
                return !Number.isNaN(Val2) ? DoThrow('NaN mismatch') : true;
        case 'string':
        case 'boolean':
            return Val1!==Val2 ? DoThrow('Value mismatch') : true;
        case 'function':
            if(Val1.prototype!==Val2.prototype)
                return DoThrow('Prototype mismatch');
            if(Val1!==Val2)
                return DoThrow('Function mismatch');
            return true;
        default:
            return DoThrow('Val1 is unknown type');
    }
}

答案 66 :(得分:0)

这是我解决这个问题的方法。我不认为我很好,但它适用于任何类型的对象比较

$str = "*POST BUS*1300*2017-9-1*1*LUSAKA*JEFF SAKALA*";
$exp = explode('*', $str);
$service = $exp[1];
$time = $exp[2];
$date = $exp[3];

答案 67 :(得分:0)

这是通用的相等检查函数,它接收元素数组作为输入并将它们相互比较。适用于所有类型的元素。

const isEqual = function(inputs = []) {
  // Checks an element if js object.
  const isObject = function(data) {
    return Object.prototype.toString.call(data) === '[object Object]';
  };
  // Sorts given object by its keys.
  const sortObjectByKey = function(obj) {
    const self = this;
    if (!obj) return {};
    return Object.keys(obj).sort().reduce((initialVal, item) => {
      initialVal[item] = !Array.isArray(obj[item]) &&
        typeof obj[item] === 'object'
        ? self.objectByKey(obj[item])
        : obj[item];
      return initialVal;
    }, {});
  };

  // Checks equality of all elements in the input against each other. Returns true | false
  return (
    inputs
      .map(
        input =>
          typeof input == 'undefined'
            ? ''
            : isObject(input)
                ? JSON.stringify(sortObjectByKey(input))
                : JSON.stringify(input)
      )
      .reduce(
        (prevValue, input) =>
          prevValue === '' || prevValue === input ? input : false,
        ''
      ) !== false
  );
};

// Tests (Made with Jest test framework.)
test('String equality check', () => {
  expect(isEqual(['murat'])).toEqual(true);
  expect(isEqual(['murat', 'john', 'doe'])).toEqual(false);
  expect(isEqual(['murat', 'murat', 'murat'])).toEqual(true);
});

test('Float equality check', () => {
  expect(isEqual([7.89, 3.45])).toEqual(false);
  expect(isEqual([7, 7.50])).toEqual(false);
  expect(isEqual([7.50, 7.50])).toEqual(true);
  expect(isEqual([7, 7])).toEqual(true);
  expect(isEqual([0.34, 0.33])).toEqual(false);
  expect(isEqual([0.33, 0.33])).toEqual(true);
});

test('Array equality check', () => {
  expect(isEqual([[1, 2, 3], [1, 2, 3]])).toEqual(true);
  expect(isEqual([[1, 3], [1, 2, 3]])).toEqual(false);
  expect(isEqual([['murat', 18], ['murat', 18]])).toEqual(true);
});

test('Object equality check', () => {
  let obj1 = {
    name: 'murat',
    age: 18
  };
  let obj2 = {
    name: 'murat',
    age: 18
  };
  let obj3 = {
    age: 18,
    name: 'murat'
  };
  let obj4 = {
    name: 'murat',
    age: 18,
    occupation: 'nothing'
  };
  expect(isEqual([obj1, obj2])).toEqual(true);
  expect(isEqual([obj1, obj2, obj3])).toEqual(true);
  expect(isEqual([obj1, obj2, obj3, obj4])).toEqual(false);
});

test('Weird equality checks', () => {
  expect(isEqual(['', {}])).toEqual(false);
  expect(isEqual([0, '0'])).toEqual(false);
});

There is also a gist

答案 68 :(得分:0)

我实现了一个方法,它接受两个jsons并检查它们的键是否使用递归具有相同的值。 我使用another question来解决这个问题。

&#13;
&#13;
const arraysEqual = (a, b) => {
    if (a === b)
        return true;
    if (a === null || b === null)
        return false;
    if (a.length !== b.length)
        return false;

    // If you don't care about the order of the elements inside
    // the array, you should sort both arrays here.

    for (let i = 0; i < a.length; ++i) {
        if (a[i] !== b[i])
            return false;
    }
    return true;
};

const jsonsEqual = (a, b) => {

  if(typeof a !== 'object' || typeof b !== 'object')
      return false;

  if (Object.keys(a).length === Object.keys(b).length) { // if items have the same size
      let response = true;

      for (let key in a) {
          if (!b[key]) // if not key
              response = false;
          if (typeof a[key] !== typeof b[key]) // if typeof doesn't equals
              response = false;
          else {
              if (Array.isArray(a[key])) // if array
                  response = arraysEqual(a[key], b[key]);
              else if (typeof a[key] === 'object') // if another json
                  response = jsonsEqual(a[key], b[key]);
              else if (a[key] !== b[key])  // not equals
                  response = false;
          }
          if (!response) // return if one item isn't equal
              return false;
      }
  } else
      return false;

  return true;
};

const json1 = { 
  a: 'a', 
  b: 'asd', 
  c: [
    '1',
    2,
    2.5,
    '3', 
    {
      d: 'asd',
      e: [
        1.6,
        { 
          f: 'asdasd',
          g: '123'
        }
      ]
    }
  ],
  h: 1,
  i: 1.2,
};

const json2 = {
  a: 'nops',
  b: 'asd'
};

const json3 = { 
  a: 'h', 
  b: '484', 
  c: [
    3,
    4.5,
    '2ss', 
    {
      e: [
        { 
          f: 'asdasd',
          g: '123'
        }
      ]
    }
  ],
  h: 1,
  i: 1.2,
};

const result = jsonsEqual(json1,json2);
//const result = jsonsEqual(json1,json3);
//const result = jsonsEqual(json1,json1);

if(result) // is equal
  $('#result').text("Jsons are the same")
else
  $('#result').text("Jsons aren't equals")
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="result"></div>
&#13;
&#13;
&#13;

答案 69 :(得分:0)

很多好主意!这是我的深度平等版本。我把它发布在github上并围绕它编写了一些测试。很难涵盖所有可能的情况,有时候没有必要这样做。

我介绍了NaN !== NaN以及循环依赖。

https://github.com/ryancat/simple-deep-equal/blob/master/index.js

答案 70 :(得分:0)

     let user1 = {
        name: "John",
        address: {
            line1: "55 Green Park Road",
            line2: {
              a:[1,2,3]
            } 
        },
        email:null
        }
    
     let user2 = {
        name: "John",
        address: {
            line1: "55 Green Park Road",
            line2: {
              a:[1,2,3]
            } 
        },
        email:null
         }
    
    // Method 1
    
    function isEqual(a, b) {
          return JSON.stringify(a) === JSON.stringify(b);
    }
    
    // Method 2
    
    function isEqual(a, b) {
      // checking type of a And b
      if(typeof a !== 'object' || typeof b !== 'object') {
        return false;
      }
      
      // Both are NULL
      if(!a && !b ) {
         return true;
      } else if(!a || !b) {
         return false;
      }
      
      let keysA = Object.keys(a);
      let keysB = Object.keys(b);
      if(keysA.length !== keysB.length) {
        return false;
      }
      for(let key in a) {
       if(!(key in b)) {
         return false;
       }
        
       if(typeof a[key] === 'object') {
         if(!isEqual(a[key], b[key]))
           {
             return false;
           }
       } else {
         if(a[key] !== b[key]) {
           return false;
         }
       }
      }
      
      return true;
    }



console.log(isEqual(user1,user2));

答案 71 :(得分:0)

function isDeepEqual(obj1, obj2, testPrototypes = false) {
  if (obj1 === obj2) {
    return true
  }

  if (typeof obj1 === "function" && typeof obj2 === "function") {
    return obj1.toString() === obj2.toString()
  }

  if (obj1 instanceof Date && obj2 instanceof Date) {
    return obj1.getTime() === obj2.getTime()
  }

  if (
    Object.prototype.toString.call(obj1) !==
      Object.prototype.toString.call(obj2) ||
    typeof obj1 !== "object"
  ) {
    return false
  }

  const prototypesAreEqual = testPrototypes
    ? isDeepEqual(
        Object.getPrototypeOf(obj1),
        Object.getPrototypeOf(obj2),
        true
      )
    : true

  const obj1Props = Object.getOwnPropertyNames(obj1)
  const obj2Props = Object.getOwnPropertyNames(obj2)

  return (
    obj1Props.length === obj2Props.length &&
    prototypesAreEqual &&
    obj1Props.every(prop => isDeepEqual(obj1[prop], obj2[prop]))
  )
}

console.log(isDeepEqual({key: 'one'}, {key: 'first'}))
console.log(isDeepEqual({key: 'one'}, {key: 'one'}))

答案 72 :(得分:-1)

我之前添加了一个答案,但它并不完美,但这将检查对象的相等性

function equalObjects(myObj1, myObj2){

let firstScore = 0;
let secondScore = 0;
let index=0;

let proprtiesArray = [];
let valuesArray = [];


let firstLength = 0;
let secondLength = 0;


for (const key in myObj1) {
    if (myObj1.hasOwnProperty(key)) {
        firstLength += 1;
        proprtiesArray.push(key);
        valuesArray.push(myObj1[key]);        
        firstScore +=1;
    }
}

for (const key in myObj2) {
    if (myObj2.hasOwnProperty(key)) {
        secondLength += 1;
        if (valuesArray[index] === myObj2[key] && proprtiesArray[index] === key) {
          secondScore +=1;
        }
        //console.log(myObj[key]);
        
        index += 1;
    }
    
}

if (secondScore == firstScore && firstLength === secondLength) {
   console.log("true", "equal objects");
   return true;
} else {
   console.log("false", "not equal objects");
   return false;
}

}

equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName':'Lovelace'});

equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName1':'Lovelace'});

equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName':'Lovelace', 'missing': false});