严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?

堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。


当前回答

从我的个人库中取出,我经常用它来工作。下面的函数是一个宽大的递归深度等号,它不检查

阶级平等 继承的值 价值观严格平等

我主要用这个来检查我是否得到了对各种API实现的相等的回复。可能会出现实现差异(如字符串与数字)和额外的空值。

它的实现非常简单(如果去掉所有注释的话)

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

其他回答

在React中,你可以使用' React -fast-compare'中的isEqual。这个答案可能不适用于纯JavaScript,但在使用React时可能有用。

console.log(isEqual({ hello: 'world' }, { hello: 'world' })) // returns true

React中最快的深度相等比较。非常快速的通用深度比较。非常适合React。备忘录和shouldComponentUpdate。

更多信息可以在这里找到:https://www.npmjs.com/package/react-fast-compare。

这是一个经典的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

这是一个非常干净的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"})

我不是Javascript专家,但这里有一个简单的解决方法。我检查三件事:

它是一个对象,而且它不是null,因为typeof null是对象。 如果两个对象的属性计数相同?否则它们就不相等。 遍历一个对象的属性,并检查对应的属性在第二个对象中是否具有相同的值。

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

这取决于你对平等的定义。因此,作为类的开发人员,要由您来定义它们的相等性。

有时会使用一种情况,如果两个实例指向内存中的相同位置,则认为它们是“相等的”,但这并不总是您想要的。例如,如果我有一个Person类,如果两个Person对象具有相同的Last Name、First Name和Social Security Number(即使它们指向内存中的不同位置),我可能会认为它们是“相等的”。

另一方面,我们不能简单地说两个对象是相等的,如果它们的每个成员的值都相同,因为,有时,你并不想这样。换句话说,对于每个类,由类开发人员定义组成对象“标识”的成员并开发适当的相等操作符(通过重载==操作符或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).