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

时间:2023-02-10 22:58:45

A strict equality operator will tell you if two object types are equal. However, is there a way to tell if two objects are equal, much like the hash code value in Java?

一个严格的等式运算符会告诉你两个对象类型是否相等。但是,是否有一种方法可以判断两个对象是否相等,就像Java中的散列代码值一样?

Stack Overflow question Is there any kind of hashCode function in JavaScript? is similar to this question, but requires a more academic answer. The scenario above demonstrates why it would be necessary to have one, and I'm wondering if there is any equivalent solution.

栈溢出问题JavaScript中有什么哈希码函数吗?与这个问题相似,但需要一个更学术性的答案。上面的场景演示了为什么有必要有一个这样的解决方案,我想知道是否有任何等价的解决方案。

50 个解决方案

#1


137  

The short answer

简短的回答

The simple answer is: No, there is no generic means to determine that an object is equal to another in the sense you mean. The exception is when you are strictly thinking of an object being typeless.

简单的答案是:不,没有通用的方法来确定一个物体和另一个物体在某种意义上是相等的。唯一的例外是严格地认为对象是无类型的。

The long answer

长答案

The concept is that of an Equals method that compares two different instances of an object to indicate whether they are equal at a value level. However, it is up to the specific type to define how an Equals method should be implemented. An iterative comparison of attributes that have primitive values may not be enough, there may well be attributes which are not to be considered part of the object value. For example,

概念是一个Equals方法,它比较对象的两个不同实例,以指示它们是否在一个值级别上相等。但是,它取决于特定类型来定义如何实现Equals方法。对具有原始值的属性进行迭代比较可能还不够,可能有一些属性不被视为对象值的一部分。例如,

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

In this above case, c is not really important to determine whether any two instances of MyClass are equal, only a and b are important. In some cases c might vary between instances and yet not be significant during comparison.

在上面的例子中,c并不是很重要的决定是否有两个MyClass的实例是相等的,只有a和b是重要的。在某些情况下,c在实例之间可能会有所不同,但在比较中却不显著。

Note this issue applies when members may themselves also be instances of a type and these each would all be required to have a means of determining equality.

注意,当成员本身也是类型的实例时,这一问题也适用,并且每个实例都必须具有确定平等的手段。

Further complicating things is that in JavaScript the distinction between data and method is blurred.

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

An object may reference a method that is to be called as an event handler, and this would likely not be considered part of its 'value state'. Whereas another object may well be assigned a function that performs an important calculation and thereby makes this instance different from others simply because it references a different function.

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

What about an object that has one of its existing prototype methods overridden by another function? Could it still be considered equal to another instance that it otherwise identical? That question can only be answered in each specific case for each type.

如果一个对象的一个现有原型方法被另一个函数覆盖,该怎么办?它是否仍然可以被认为等于另一个相同的实例?这个问题只能在每种特定情况下回答。

As stated earlier, the exception would be a strictly typeless object. In which case the only sensible choice is an iterative and recursive comparison of each member. Even then one has to ask what is the 'value' of a function?

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

#2


404  

Why reinvent the wheel? Give Lodash a try. It has a number of must-have functions such as isEqual().

为什么重新发明*?给Lodash一试。它有许多必须具备的功能,如isEqual()。

_.isEqual(object, other);

It will brute force check each key value - just like the other examples on this page - using ECMAScript 5 and native optimizations if they're available in the browser.

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

Note: Previously this answer recommended Underscore.js, but lodash has done a better job of getting bugs fixed and addressing issues with consistency.

注意:之前这个答案建议使用下划线。但是lodash在修复bug和解决问题的一致性方面做得更好。

#3


134  

The default equality operator in JavaScript for Objects yields true when they refer to the same location in memory.

当对象引用内存中的相同位置时,JavaScript中的默认相等运算符将返回true。

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

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

If you require a different equality operator you'll need to add an equals(other) method, or something like it to your classes and the specifics of your problem domain will determine what exactly that means.

如果您需要一个不同的等式运算符,您需要添加一个equals(other)方法,或者类似的方法到您的类中,您的问题域的具体细节将决定它的确切含义。

Here's a playing card example:

这里有一个打牌的例子:

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

#4


63  

If you are working in AngularJS, the angular.equals function will determine if two objects are equal. In Ember.js use isEqual.

如果你用的是角度,角度。equals function将确定两个对象是否相等。在安博。js isEqual使用。

  • angular.equals - See the docs or source for more on this method. It does a deep compare on arrays too.
  • 角。= -关于这个方法的更多信息,请参阅文档或源代码。它也对数组做了深入的比较。
  • Ember.js isEqual - See the docs or source for more on this method. It does not do a deep compare on arrays.
  • 安博。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>

#5


44  

If you are using a JSON library, you can encode each object as JSON, then compare the resulting strings for equality.

如果您使用的是JSON库,则可以将每个对象编码为JSON,然后将得到的字符串与相等的字符串进行比较。

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

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

NOTE: While this answer will work in many cases, as several people have pointed out in the comments it's problematic for a variety of reasons. In pretty much all cases you'll want to find a more robust solution.

注意:虽然这个答案在很多情况下都是有效的,但正如一些人在评论中指出的那样,这个答案存在问题的原因有很多。在几乎所有的情况下,您都希望找到一个更健壮的解决方案。

#6


41  

This is my version. It is using new Object.keys feature that is introduced in ES5 and ideas/tests from +, + and +:

这是我的版本。它正在使用新对象。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 * 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 } }));

#7


20  

If you have a deep copy function handy, you can use the following trick to still use JSON.stringify while matching the order of properties:

如果手边有一个深度复制函数,您可以使用以下技巧来仍然使用JSON。在匹配属性的顺序时进行弦化:

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

Demo: http://jsfiddle.net/CU3vb/3/

演示:http://jsfiddle.net/CU3vb/3/

Rationale:

理由是:

Since the properties of obj1 are copied to the clone one by one, their order in the clone will be preserved. And when the properties of obj2 are copied to the clone, since properties already existing in obj1 will simply be overwritten, their orders in the clone will be preserved.

由于obj1的属性被一个一个地复制到克隆,它们在克隆中的顺序将被保留。并且当obj2的属性被复制到克隆时,因为在obj1中已经存在的属性将被简单地覆盖,它们在克隆中的顺序将被保留。

#8


17  

Short functional deepEqual implementation:

短的功能性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);
}

Edit: version 2, using jib's suggestion and ES6 arrow functions:

编辑:版本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);
}

#9


14  

Are you trying to test if two objects are the equal? ie: their properties are equal?

你在测试两个物体是否相等吗?它们的性质是相等的吗?

If this is the case, you'll probably have noticed this situation:

如果是这样的话,你可能已经注意到了这种情况:

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

you might have to do something like this:

你可能要做这样的事情:

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

Obviously that function could do with quite a bit of optimisation, and the ability to do deep checking (to handle nested objects: var a = { foo : { fu : "bar" } }) but you get the idea.

显然,这个函数可以进行相当多的优化,并且能够进行深度检查(以处理嵌套对象:var a = {foo: {fu}}),但是您可以理解这个想法。

As FOR pointed out, you might have to adapt this for your own purposes, eg: different classes may have different definitions of "equal". If you're just working with plain objects, the above may suffice, otherwise a custom MyClass.equals() function may be the way to go.

如前所述,您可能需要根据自己的目的调整它,例如:不同的类可能有不同的“equal”定义。如果您只是使用普通对象,上面的内容可能就足够了,否则可以使用自定义的MyClass.equals()函数。

#10


13  

In Node.js, you can use its native require("assert").deepEqual. More info: http://nodejs.org/api/assert.html

在节点。js,可以使用它的native require(“assert”). deepequal。更多信息:http://nodejs.org/api/assert.html。

For example:

例如:

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

Another example that returns true / false instead of returning errors:

另一个返回真/假而不返回错误的例子:

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


8  

I use this comparable function to produce copies of my objects that are JSON 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>

Comes in handy in tests (most test frameworks have an is function). E.g.

在测试中派上用场(大多数测试框架都有一个功能)。如。

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

If a difference is caught, strings get logged, making differences spottable:

如果发现一个差异,字符串将被记录下来,使差异具有可寻址性:

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


8  

Heres's a solution in ES6/ES2015 using a functional-style approach:

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

demo available here

这里演示可用

#13


8  

Simplest and logical solutions for comparing everything Like Object, Array, String, Int...

用于比较对象、数组、字符串、Int等所有事物的最简单和逻辑的解决方案。

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

JSON。stringify({答:val1 })= = = JSON。stringify({答:val2 })

Note:

注意:

  • you need to replace val1and val2 with your Object
  • 您需要用对象替换val1和val2
  • for the object, you have to sort(by key) recursively for both side objects
  • 对于对象,您必须递归地对两边的对象排序(按键)。

#14


7  

A simple solution to this issue that many people don't realize is to sort the JSON strings (per character). This is also usually faster than the other solutions mentioned here:

许多人没有意识到的一个简单的解决方案是对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(''));
}

Another useful thing about this method is you can filter comparisons by passing a "replacer" function to the JSON.stringify functions (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Example_of_using_replacer_parameter). The following will only compare all objects keys that are named "derp":

这个方法的另一个有用之处是,您可以通过将“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;
});

#15


4  

you can use _.isEqual(obj1, obj2) from the underscore.js library.

您可以使用_。isEqual(obj1, obj2)来自下划线。js库。

Here is an example:

这是一个例子:

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

See the official documentation from here: http://underscorejs.org/#isEqual

参见这里的官方文档:http://underscorejs.org/#isEqual。

#16


3  

I'd advise against hashing or serialization (as the JSON solution suggest). If you need to test if two objects are equal, then you need to define what equals means. It could be that all data members in both objects match, or it could be that must the memory locations match (meaning both variables reference the same object in memory), or may be that only one data member in each object must match.

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

Recently I developed an object whose constructor creates a new id (starting from 1 and incrementing by 1) each time an instance is created. This object has an isEqual function that compares that id value with the id value of another object and returns true if they match.

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

In that case I defined "equal" as meaning the the id values match. Given that each instance has a unique id this could be used to enforce the idea that matching objects also occupy the same memory location. Although that is not necessary.

在这种情况下,我将“equal”定义为id值匹配。假设每个实例都有一个唯一的id,那么可以使用它来实现匹配对象也占用相同的内存位置的想法。虽然这不是必须的。

#17


3  

Needing a more generic object comparison function than had been posted, I cooked up the following. Critique appreciated...

我需要一个比之前发布的更通用的对象比较函数,因此编写了下面的代码。批判赞赏……

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

#18


3  

If you are comparing JSON objects you can use https://github.com/mirek/node-rus-diff

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

npm install rus-diff

Usage:

用法:

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

If two objects are different, a MongoDB compatible {$rename:{...}, $unset:{...}, $set:{...}} like object is returned.

如果两个对象不同,MongoDB兼容的{$rename:{…},设置美元:{…},美元:{…类}对象被返回。

#19


3  

If you're using ES6+ via Babel or otherwise, you can also use Object.is(x, y).

如果你是通过Babel或者其他方式使用ES6+,你也可以使用Object。(x,y)。

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

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

#20


3  

I faced the same problem and deccided to write my own solution. But because I want to also compare Arrays with Objects and vice-versa, I crafted a generic solution. I decided to add the functions to the prototype, but one can easily rewrite them to standalone functions. Here is the code:

我也遇到了同样的问题,于是决定写自己的解决方案。但是因为我也想将数组与对象进行比较,反之亦然,所以我设计了一个通用的解决方案。我决定将函数添加到原型中,但是可以很容易地将它们重写为独立的函数。这是代码:

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

This Algorithm is split into two parts; The equals function itself and a function to find the numeric index of a property in an array / object. The find function is only needed because indexof only finds numbers and strings and no objects .

该算法分为两部分;等于函数本身和查找数组/对象中属性的数值索引的函数。查找函数只需要,因为indexof只查找数字和字符串,不查找对象。

One can call it like this:

我们可以这样称呼它:

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

The function either returns true or false, in this case true. The algorithm als allows comparison between very complex objects:

函数要么返回true,要么返回false,在本例中为true。算法als允许在非常复杂的对象之间进行比较:

({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"]})

The upper example will return true, even tho the properties have a different ordering. One small detail to look out for: This code also checks for the same type of two variables, so "3" is not the same as 3.

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

#21


3  

I don't know if anyone's posted anything similar to this, but here's a function I made to check for object equalities.

我不知道是否有人发布过类似的东西,但这里有一个函数,用来检查对象的等式。

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

Also, it's recursive, so it can also check for deep equality, if that's what you call it.

而且,它是递归的,所以它也可以检查深层等式,如果你叫它深层等式的话。

#22


3  

The Object.is() method determines whether two values are the same value.

Object.is()方法确定两个值是否相同。

Syntax

语法

Object.is(value1, value2);

Parameters

参数

value1: The first value to compare.

value1:要比较的第一个值。

value2: The second value to compare.

值2:第二个要比较的值。

Return value

返回值

A Boolean indicating whether or not the two arguments are the same value.

指示两个参数是否为相同值的布尔值。

Examples

例子

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

if you want more info read this, link

如果你想了解更多信息,请点击链接

#23


2  

It's useful to consider two objects equal if they have all the same values for all properties and recursively for all nested objects and arrays. I also consider the following two objects equal:

如果两个对象具有相同的所有属性值,并递归地遍历所有嵌套的对象和数组,那么考虑两个对象是很有用的。我还认为下列两个对象是相等的:

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

Similarly, arrays can have "missing" elements and undefined elements. I would treat those the same as well:

类似地,数组可以有“缺失”的元素和未定义的元素。我也会同样对待他们:

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

A function that implements this definition of equality:

实现平等定义的函数:

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 (including the helper functions, generalType and uniqueArray): Unit Test and Test Runner here.

源代码(包括辅助函数、通用类型和unique earray):单元测试和测试运行器。

#24


2  

I'm making the following assumptions with this function:

我用这个函数做如下假设:

  1. You control the objects you are comparing and you only have primitive values (ie. not nested objects, functions, etc.).
  2. 你控制你正在比较的对象,你只有原始的值。不是嵌套对象、函数等等)。
  3. Your browser has support for Object.keys.
  4. 您的浏览器支持Object.keys。

This should be treated as a demonstration of a simple strategy.

这应该被视为一个简单策略的示范。

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

#25


2  

This is an addition for all the above, not a replacement. If you need to fast shallow-compare objects without need to check extra recursive cases. Here is a shot.

这是所有上述的补充,而不是替代。如果您需要快速地对对象进行浅比较,而不需要检查额外的递归情况。这是一个机会。

This compares for: 1) Equality of number of own properties, 2) Equality of key names, 3) if bCompareValues == true, Equality of corresponding property values and their types (triple equality)

比较如下: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;
}

#26


2  

For comparing keys for simple key/value pairs object instances, I use:

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

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

Once keys are compared, a simple additional for..in loop is enough.

一旦键被比较,一个简单的附加。在循环就足够了。

Complexity is O(N*N) with N is the number of keys.

复杂度是O(N*N), N是键的个数。

I hope/guess objects I define won't hold more than 1000 properties...

我希望我定义的对象不会包含超过1000个属性……

#27


2  

I know this is a bit old, but I would like to add a solution that I came up with for this problem. I had an object and I wanted to know when its data changed. "something similar to Object.observe" and what I did was:

我知道这有点旧了,但我想添加一个我为这个问题想出的解决方案。我有一个对象,我想知道它的数据何时改变。“类似的对象。观察"我所做的是:

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

This here can be duplicated and create an other set of arrays to compare the values and keys. It is very simple because they are now arrays and will return false if objects have different sizes.

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

#28


2  

Pulling out from my personal library, which i use for my work repeatedly. The following function is a lenient recursive deep equal, which does not check

从我的私人图书馆里抽出来,这是我反复使用的。下面的函数是一个宽大的递归深度相等,它不检查

  • Class equality
  • 阶级平等
  • Inherited values
  • 继承的值
  • Values strict equality
  • 值严格平等

I mainly use this to check if i get equal replies against various API implementation. Where implementation difference (like string vs number) and additional null values, can occur.

我主要用它来检查我是否在不同的API实现中得到了相同的回复。实现差异(如字符串与数字)和附加的空值。

Its implementation is quite straightforward and short (if all the comments is stripped off)

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

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

#29


2  

Just wanted to contribute my version of objects comparison utilizing some es6 features. It doesn't take an order into account. After converting all if/else's to ternary I've came with following:

只是想利用一些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;

        }
    )
}

#30


1  

Depends on what you mean by equality. And therefore it is up to you, as the developer of the classes, to define their equality.

这取决于你所说的平等。因此,作为类的开发人员,您可以定义它们的相等性。

There's one case used sometimes, where two instances are considered 'equal' if they point to the same location in memory, but that is not always what you want. For instance, if I have a Person class, I might want to consider two Person objects 'equal' if they have the same Last Name, First Name, and Social Security Number (even if they point to different locations in memory).

有时会用到一个例子,如果两个实例在内存中指向相同的位置,它们被认为是相等的,但这并不总是你想要的。例如,如果我有一个Person类,如果两个Person对象具有相同的姓、名和社会保险号(即使它们指向内存中的不同位置),我可能会认为它们是“相等的”。

On the other hand, we can't simply say that two objects are equal if the value of each of their members is the same, since, sometimes, you don't want that. In other words, for each class, it's up to the class developer to define what members make up the objects 'identity' and develop a proper equality operator (be it via overloading the == operator or an Equals method).

另一方面,我们不能简单地说两个对象是相等的,如果它们的每个成员的值是相同的,因为,有时候,你不需要它。换句话说,对于每个类,由类开发人员定义组成对象“标识”的成员,并开发适当的等式运算符(通过重载=运算符或Equals方法)。

Saying that two objects are equal if they have the same hash is one way out. However you then have to wonder how the hash is calculated for each instance. Going back to the Person example above, we could use this system if the hash was calculated by looking at the values of the First Name, Last Name, and Social Security Number fields. On top of that, we are then relying on the quality of the hashing method (that's a huge topic on its own, but suffice it to say that not all hashes are created equal, and bad hashing methods can lead to more collisions, which in this case would return false matches).

如果两个对象有相同的散列,那么两个对象是相等的。但是,您必须考虑如何为每个实例计算散列。回到上面的Person示例,如果通过查看姓名、姓氏和社会保障号码字段的值来计算散列,我们可以使用这个系统。最重要的是,我们是那么依赖质量的哈希方法(这是一个巨大的话题,只想说,并非所有的散列值都是平等的,和坏的哈希方法会导致更多的冲突,在这种情况下,将返回错误的匹配)。

#1


137  

The short answer

简短的回答

The simple answer is: No, there is no generic means to determine that an object is equal to another in the sense you mean. The exception is when you are strictly thinking of an object being typeless.

简单的答案是:不,没有通用的方法来确定一个物体和另一个物体在某种意义上是相等的。唯一的例外是严格地认为对象是无类型的。

The long answer

长答案

The concept is that of an Equals method that compares two different instances of an object to indicate whether they are equal at a value level. However, it is up to the specific type to define how an Equals method should be implemented. An iterative comparison of attributes that have primitive values may not be enough, there may well be attributes which are not to be considered part of the object value. For example,

概念是一个Equals方法,它比较对象的两个不同实例,以指示它们是否在一个值级别上相等。但是,它取决于特定类型来定义如何实现Equals方法。对具有原始值的属性进行迭代比较可能还不够,可能有一些属性不被视为对象值的一部分。例如,

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

In this above case, c is not really important to determine whether any two instances of MyClass are equal, only a and b are important. In some cases c might vary between instances and yet not be significant during comparison.

在上面的例子中,c并不是很重要的决定是否有两个MyClass的实例是相等的,只有a和b是重要的。在某些情况下,c在实例之间可能会有所不同,但在比较中却不显著。

Note this issue applies when members may themselves also be instances of a type and these each would all be required to have a means of determining equality.

注意,当成员本身也是类型的实例时,这一问题也适用,并且每个实例都必须具有确定平等的手段。

Further complicating things is that in JavaScript the distinction between data and method is blurred.

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

An object may reference a method that is to be called as an event handler, and this would likely not be considered part of its 'value state'. Whereas another object may well be assigned a function that performs an important calculation and thereby makes this instance different from others simply because it references a different function.

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

What about an object that has one of its existing prototype methods overridden by another function? Could it still be considered equal to another instance that it otherwise identical? That question can only be answered in each specific case for each type.

如果一个对象的一个现有原型方法被另一个函数覆盖,该怎么办?它是否仍然可以被认为等于另一个相同的实例?这个问题只能在每种特定情况下回答。

As stated earlier, the exception would be a strictly typeless object. In which case the only sensible choice is an iterative and recursive comparison of each member. Even then one has to ask what is the 'value' of a function?

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

#2


404  

Why reinvent the wheel? Give Lodash a try. It has a number of must-have functions such as isEqual().

为什么重新发明*?给Lodash一试。它有许多必须具备的功能,如isEqual()。

_.isEqual(object, other);

It will brute force check each key value - just like the other examples on this page - using ECMAScript 5 and native optimizations if they're available in the browser.

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

Note: Previously this answer recommended Underscore.js, but lodash has done a better job of getting bugs fixed and addressing issues with consistency.

注意:之前这个答案建议使用下划线。但是lodash在修复bug和解决问题的一致性方面做得更好。

#3


134  

The default equality operator in JavaScript for Objects yields true when they refer to the same location in memory.

当对象引用内存中的相同位置时,JavaScript中的默认相等运算符将返回true。

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

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

If you require a different equality operator you'll need to add an equals(other) method, or something like it to your classes and the specifics of your problem domain will determine what exactly that means.

如果您需要一个不同的等式运算符,您需要添加一个equals(other)方法,或者类似的方法到您的类中,您的问题域的具体细节将决定它的确切含义。

Here's a playing card example:

这里有一个打牌的例子:

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

#4


63  

If you are working in AngularJS, the angular.equals function will determine if two objects are equal. In Ember.js use isEqual.

如果你用的是角度,角度。equals function将确定两个对象是否相等。在安博。js isEqual使用。

  • angular.equals - See the docs or source for more on this method. It does a deep compare on arrays too.
  • 角。= -关于这个方法的更多信息,请参阅文档或源代码。它也对数组做了深入的比较。
  • Ember.js isEqual - See the docs or source for more on this method. It does not do a deep compare on arrays.
  • 安博。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>

#5


44  

If you are using a JSON library, you can encode each object as JSON, then compare the resulting strings for equality.

如果您使用的是JSON库,则可以将每个对象编码为JSON,然后将得到的字符串与相等的字符串进行比较。

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

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

NOTE: While this answer will work in many cases, as several people have pointed out in the comments it's problematic for a variety of reasons. In pretty much all cases you'll want to find a more robust solution.

注意:虽然这个答案在很多情况下都是有效的,但正如一些人在评论中指出的那样,这个答案存在问题的原因有很多。在几乎所有的情况下,您都希望找到一个更健壮的解决方案。

#6


41  

This is my version. It is using new Object.keys feature that is introduced in ES5 and ideas/tests from +, + and +:

这是我的版本。它正在使用新对象。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 * 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 } }));

#7


20  

If you have a deep copy function handy, you can use the following trick to still use JSON.stringify while matching the order of properties:

如果手边有一个深度复制函数,您可以使用以下技巧来仍然使用JSON。在匹配属性的顺序时进行弦化:

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

Demo: http://jsfiddle.net/CU3vb/3/

演示:http://jsfiddle.net/CU3vb/3/

Rationale:

理由是:

Since the properties of obj1 are copied to the clone one by one, their order in the clone will be preserved. And when the properties of obj2 are copied to the clone, since properties already existing in obj1 will simply be overwritten, their orders in the clone will be preserved.

由于obj1的属性被一个一个地复制到克隆,它们在克隆中的顺序将被保留。并且当obj2的属性被复制到克隆时,因为在obj1中已经存在的属性将被简单地覆盖,它们在克隆中的顺序将被保留。

#8


17  

Short functional deepEqual implementation:

短的功能性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);
}

Edit: version 2, using jib's suggestion and ES6 arrow functions:

编辑:版本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);
}

#9


14  

Are you trying to test if two objects are the equal? ie: their properties are equal?

你在测试两个物体是否相等吗?它们的性质是相等的吗?

If this is the case, you'll probably have noticed this situation:

如果是这样的话,你可能已经注意到了这种情况:

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

you might have to do something like this:

你可能要做这样的事情:

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

Obviously that function could do with quite a bit of optimisation, and the ability to do deep checking (to handle nested objects: var a = { foo : { fu : "bar" } }) but you get the idea.

显然,这个函数可以进行相当多的优化,并且能够进行深度检查(以处理嵌套对象:var a = {foo: {fu}}),但是您可以理解这个想法。

As FOR pointed out, you might have to adapt this for your own purposes, eg: different classes may have different definitions of "equal". If you're just working with plain objects, the above may suffice, otherwise a custom MyClass.equals() function may be the way to go.

如前所述,您可能需要根据自己的目的调整它,例如:不同的类可能有不同的“equal”定义。如果您只是使用普通对象,上面的内容可能就足够了,否则可以使用自定义的MyClass.equals()函数。

#10


13  

In Node.js, you can use its native require("assert").deepEqual. More info: http://nodejs.org/api/assert.html

在节点。js,可以使用它的native require(“assert”). deepequal。更多信息:http://nodejs.org/api/assert.html。

For example:

例如:

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

Another example that returns true / false instead of returning errors:

另一个返回真/假而不返回错误的例子:

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


8  

I use this comparable function to produce copies of my objects that are JSON 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>

Comes in handy in tests (most test frameworks have an is function). E.g.

在测试中派上用场(大多数测试框架都有一个功能)。如。

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

If a difference is caught, strings get logged, making differences spottable:

如果发现一个差异,字符串将被记录下来,使差异具有可寻址性:

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


8  

Heres's a solution in ES6/ES2015 using a functional-style approach:

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

demo available here

这里演示可用

#13


8  

Simplest and logical solutions for comparing everything Like Object, Array, String, Int...

用于比较对象、数组、字符串、Int等所有事物的最简单和逻辑的解决方案。

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

JSON。stringify({答:val1 })= = = JSON。stringify({答:val2 })

Note:

注意:

  • you need to replace val1and val2 with your Object
  • 您需要用对象替换val1和val2
  • for the object, you have to sort(by key) recursively for both side objects
  • 对于对象,您必须递归地对两边的对象排序(按键)。

#14


7  

A simple solution to this issue that many people don't realize is to sort the JSON strings (per character). This is also usually faster than the other solutions mentioned here:

许多人没有意识到的一个简单的解决方案是对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(''));
}

Another useful thing about this method is you can filter comparisons by passing a "replacer" function to the JSON.stringify functions (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Example_of_using_replacer_parameter). The following will only compare all objects keys that are named "derp":

这个方法的另一个有用之处是,您可以通过将“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;
});

#15


4  

you can use _.isEqual(obj1, obj2) from the underscore.js library.

您可以使用_。isEqual(obj1, obj2)来自下划线。js库。

Here is an example:

这是一个例子:

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

See the official documentation from here: http://underscorejs.org/#isEqual

参见这里的官方文档:http://underscorejs.org/#isEqual。

#16


3  

I'd advise against hashing or serialization (as the JSON solution suggest). If you need to test if two objects are equal, then you need to define what equals means. It could be that all data members in both objects match, or it could be that must the memory locations match (meaning both variables reference the same object in memory), or may be that only one data member in each object must match.

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

Recently I developed an object whose constructor creates a new id (starting from 1 and incrementing by 1) each time an instance is created. This object has an isEqual function that compares that id value with the id value of another object and returns true if they match.

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

In that case I defined "equal" as meaning the the id values match. Given that each instance has a unique id this could be used to enforce the idea that matching objects also occupy the same memory location. Although that is not necessary.

在这种情况下,我将“equal”定义为id值匹配。假设每个实例都有一个唯一的id,那么可以使用它来实现匹配对象也占用相同的内存位置的想法。虽然这不是必须的。

#17


3  

Needing a more generic object comparison function than had been posted, I cooked up the following. Critique appreciated...

我需要一个比之前发布的更通用的对象比较函数,因此编写了下面的代码。批判赞赏……

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

#18


3  

If you are comparing JSON objects you can use https://github.com/mirek/node-rus-diff

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

npm install rus-diff

Usage:

用法:

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

If two objects are different, a MongoDB compatible {$rename:{...}, $unset:{...}, $set:{...}} like object is returned.

如果两个对象不同,MongoDB兼容的{$rename:{…},设置美元:{…},美元:{…类}对象被返回。

#19


3  

If you're using ES6+ via Babel or otherwise, you can also use Object.is(x, y).

如果你是通过Babel或者其他方式使用ES6+,你也可以使用Object。(x,y)。

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

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

#20


3  

I faced the same problem and deccided to write my own solution. But because I want to also compare Arrays with Objects and vice-versa, I crafted a generic solution. I decided to add the functions to the prototype, but one can easily rewrite them to standalone functions. Here is the code:

我也遇到了同样的问题,于是决定写自己的解决方案。但是因为我也想将数组与对象进行比较,反之亦然,所以我设计了一个通用的解决方案。我决定将函数添加到原型中,但是可以很容易地将它们重写为独立的函数。这是代码:

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

This Algorithm is split into two parts; The equals function itself and a function to find the numeric index of a property in an array / object. The find function is only needed because indexof only finds numbers and strings and no objects .

该算法分为两部分;等于函数本身和查找数组/对象中属性的数值索引的函数。查找函数只需要,因为indexof只查找数字和字符串,不查找对象。

One can call it like this:

我们可以这样称呼它:

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

The function either returns true or false, in this case true. The algorithm als allows comparison between very complex objects:

函数要么返回true,要么返回false,在本例中为true。算法als允许在非常复杂的对象之间进行比较:

({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"]})

The upper example will return true, even tho the properties have a different ordering. One small detail to look out for: This code also checks for the same type of two variables, so "3" is not the same as 3.

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

#21


3  

I don't know if anyone's posted anything similar to this, but here's a function I made to check for object equalities.

我不知道是否有人发布过类似的东西,但这里有一个函数,用来检查对象的等式。

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

Also, it's recursive, so it can also check for deep equality, if that's what you call it.

而且,它是递归的,所以它也可以检查深层等式,如果你叫它深层等式的话。

#22


3  

The Object.is() method determines whether two values are the same value.

Object.is()方法确定两个值是否相同。

Syntax

语法

Object.is(value1, value2);

Parameters

参数

value1: The first value to compare.

value1:要比较的第一个值。

value2: The second value to compare.

值2:第二个要比较的值。

Return value

返回值

A Boolean indicating whether or not the two arguments are the same value.

指示两个参数是否为相同值的布尔值。

Examples

例子

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

if you want more info read this, link

如果你想了解更多信息,请点击链接

#23


2  

It's useful to consider two objects equal if they have all the same values for all properties and recursively for all nested objects and arrays. I also consider the following two objects equal:

如果两个对象具有相同的所有属性值,并递归地遍历所有嵌套的对象和数组,那么考虑两个对象是很有用的。我还认为下列两个对象是相等的:

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

Similarly, arrays can have "missing" elements and undefined elements. I would treat those the same as well:

类似地,数组可以有“缺失”的元素和未定义的元素。我也会同样对待他们:

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

A function that implements this definition of equality:

实现平等定义的函数:

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 (including the helper functions, generalType and uniqueArray): Unit Test and Test Runner here.

源代码(包括辅助函数、通用类型和unique earray):单元测试和测试运行器。

#24


2  

I'm making the following assumptions with this function:

我用这个函数做如下假设:

  1. You control the objects you are comparing and you only have primitive values (ie. not nested objects, functions, etc.).
  2. 你控制你正在比较的对象,你只有原始的值。不是嵌套对象、函数等等)。
  3. Your browser has support for Object.keys.
  4. 您的浏览器支持Object.keys。

This should be treated as a demonstration of a simple strategy.

这应该被视为一个简单策略的示范。

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

#25


2  

This is an addition for all the above, not a replacement. If you need to fast shallow-compare objects without need to check extra recursive cases. Here is a shot.

这是所有上述的补充,而不是替代。如果您需要快速地对对象进行浅比较,而不需要检查额外的递归情况。这是一个机会。

This compares for: 1) Equality of number of own properties, 2) Equality of key names, 3) if bCompareValues == true, Equality of corresponding property values and their types (triple equality)

比较如下: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;
}

#26


2  

For comparing keys for simple key/value pairs object instances, I use:

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

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

Once keys are compared, a simple additional for..in loop is enough.

一旦键被比较,一个简单的附加。在循环就足够了。

Complexity is O(N*N) with N is the number of keys.

复杂度是O(N*N), N是键的个数。

I hope/guess objects I define won't hold more than 1000 properties...

我希望我定义的对象不会包含超过1000个属性……

#27


2  

I know this is a bit old, but I would like to add a solution that I came up with for this problem. I had an object and I wanted to know when its data changed. "something similar to Object.observe" and what I did was:

我知道这有点旧了,但我想添加一个我为这个问题想出的解决方案。我有一个对象,我想知道它的数据何时改变。“类似的对象。观察"我所做的是:

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

This here can be duplicated and create an other set of arrays to compare the values and keys. It is very simple because they are now arrays and will return false if objects have different sizes.

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

#28


2  

Pulling out from my personal library, which i use for my work repeatedly. The following function is a lenient recursive deep equal, which does not check

从我的私人图书馆里抽出来,这是我反复使用的。下面的函数是一个宽大的递归深度相等,它不检查

  • Class equality
  • 阶级平等
  • Inherited values
  • 继承的值
  • Values strict equality
  • 值严格平等

I mainly use this to check if i get equal replies against various API implementation. Where implementation difference (like string vs number) and additional null values, can occur.

我主要用它来检查我是否在不同的API实现中得到了相同的回复。实现差异(如字符串与数字)和附加的空值。

Its implementation is quite straightforward and short (if all the comments is stripped off)

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

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

#29


2  

Just wanted to contribute my version of objects comparison utilizing some es6 features. It doesn't take an order into account. After converting all if/else's to ternary I've came with following:

只是想利用一些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;

        }
    )
}

#30


1  

Depends on what you mean by equality. And therefore it is up to you, as the developer of the classes, to define their equality.

这取决于你所说的平等。因此,作为类的开发人员,您可以定义它们的相等性。

There's one case used sometimes, where two instances are considered 'equal' if they point to the same location in memory, but that is not always what you want. For instance, if I have a Person class, I might want to consider two Person objects 'equal' if they have the same Last Name, First Name, and Social Security Number (even if they point to different locations in memory).

有时会用到一个例子,如果两个实例在内存中指向相同的位置,它们被认为是相等的,但这并不总是你想要的。例如,如果我有一个Person类,如果两个Person对象具有相同的姓、名和社会保险号(即使它们指向内存中的不同位置),我可能会认为它们是“相等的”。

On the other hand, we can't simply say that two objects are equal if the value of each of their members is the same, since, sometimes, you don't want that. In other words, for each class, it's up to the class developer to define what members make up the objects 'identity' and develop a proper equality operator (be it via overloading the == operator or an Equals method).

另一方面,我们不能简单地说两个对象是相等的,如果它们的每个成员的值是相同的,因为,有时候,你不需要它。换句话说,对于每个类,由类开发人员定义组成对象“标识”的成员,并开发适当的等式运算符(通过重载=运算符或Equals方法)。

Saying that two objects are equal if they have the same hash is one way out. However you then have to wonder how the hash is calculated for each instance. Going back to the Person example above, we could use this system if the hash was calculated by looking at the values of the First Name, Last Name, and Social Security Number fields. On top of that, we are then relying on the quality of the hashing method (that's a huge topic on its own, but suffice it to say that not all hashes are created equal, and bad hashing methods can lead to more collisions, which in this case would return false matches).

如果两个对象有相同的散列,那么两个对象是相等的。但是,您必须考虑如何为每个实例计算散列。回到上面的Person示例,如果通过查看姓名、姓氏和社会保障号码字段的值来计算散列,我们可以使用这个系统。最重要的是,我们是那么依赖质量的哈希方法(这是一个巨大的话题,只想说,并非所有的散列值都是平等的,和坏的哈希方法会导致更多的冲突,在这种情况下,将返回错误的匹配)。