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

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


当前回答

简短的回答

简单的答案是:不,没有一般的方法来确定一个对象等于另一个你所指的意义。例外情况是当您严格地认为一个对象是无类型的。

长话短说

这个概念是一个Equals方法,它比较一个对象的两个不同实例,以指示它们在值级别上是否相等。但是,定义Equals方法应该如何实现取决于具体的类型。对具有基本值的属性进行迭代比较可能还不够:对象可能包含与相等无关的属性。例如,

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

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

注意,当成员本身也可能是某个类型的实例,并且每个实例都需要有确定相等的方法时,这个问题就会出现。

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

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

如果一个对象的现有原型方法被另一个函数覆盖,该怎么办?它还能被认为与另一个相同的实例相等吗?这个问题只能在每种类型的具体情况下回答。

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

其他回答

虽然这个问题已经有很多答案了。我只是想提供另一种实现方法:

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.

需要一个比已经发布的更通用的对象比较函数,我炮制了以下。批判赞赏……

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

Const obj = { 名称:“卡尔”, 年龄:15 } Const obj2 = { 名称:“卡尔”, 年龄:15日 } const compareObj = (objects) => { Const res = objects.map((item) => { 返回Object.entries(项).flat . join () () }) 返回res.every((a) => { 返回a === res[0] }) } console.log (compareObj (obj, methoda ()))

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

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

Var object1 = { 关键:“价值” }; Var object2 = { 关键:“价值” }; Var object3 = { 键:“无值” }; console.log('object1和object2相等:',JSON.stringify(object1) === JSON.stringify(object2)); console.log('object2和object3相等:',JSON.stringify(object2) === JSON.stringify(object3));

当然,当我们在它的时候,我会抛出我自己对车轮的重新发明(我为辐条和使用的材料的数量感到自豪):

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

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,但当然,对于一个差异嵌套很深的大对象,它可能不那么有效。在我自己的场景中,良好地处理嵌套数组非常重要。

希望它能帮助需要这种“轮子”的人。