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

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


当前回答

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

npm install rus-diff

用法:

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

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

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

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

其他回答

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

有时会使用一种情况,如果两个实例指向内存中的相同位置,则认为它们是“相等的”,但这并不总是您想要的。例如,如果我有一个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).

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

我使用这个可比函数来生成JSON可比的对象副本:

Var可比= o => (typeof o != '对象' || !o)?o: 种(o) .sort()。减少((c键)= > (c[主要]=可比(o(例子)),c), {}); / /演示: var = {1, c: 4 b:[2、3],d: {e:“5”,f:零}}; var b = {b:[2、3],c: 4 d: {f: null, e:“5”},答:1}; console.log (JSON.stringify(可比(a))); console.log (JSON.stringify(可比(b))); console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b))); < div id = " div " > < / div >

在测试中很方便(大多数测试框架都有一个is函数)。如。

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

如果捕捉到差异,则记录字符串,使差异可见:

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

下面是一个使用ES6+的解决方案

// this comparison would not work for function and symbol comparisons
// this would only work best for compared objects that do not belong to same address in memory
// Returns true if there is no difference, and false otherwise


export const isObjSame = (obj1, obj2) => {
    if (typeof obj1 !== "object" && obj1 !== obj2) {
        return false;
    }

    if (typeof obj1 !== "object" && typeof obj2 !== "object" && obj1 === obj2) {
        return true;
    }

    if (typeof obj1 === "object" && typeof obj2 === "object") {
        if (Array.isArray(obj1) && Array.isArray(obj2)) {
            if (obj1.length === obj2.length) {
                if (obj1.length === 0) {
                    return true;
                }
                const firstElemType = typeof obj1[0];

                if (typeof firstElemType !== "object") {
                    const confirmSameType = currentType =>
                        typeof currentType === firstElemType;

                    const checkObjOne = obj1.every(confirmSameType);
                    const checkObjTwo = obj2.every(confirmSameType);

                    if (checkObjOne && checkObjTwo) {
                        // they are primitves, we can therefore sort before and compare by index
                        // use number sort
                        // use alphabet sort
                        // use regular sort
                        if (firstElemType === "string") {
                            obj1.sort((a, b) => a.localeCompare(b));
                            obj2.sort((a, b) => a.localeCompare(b));
                        }
                        obj1.sort((a, b) => a - b);
                        obj2.sort((a, b) => a - b);

                        let equal = true;

                        obj1.map((element, index) => {
                            if (!isObjSame(element, obj2[index])) {
                                equal = false;
                            }
                        });

                        return equal;
                    }

                    if (
                        (checkObjOne && !checkObjTwo) ||
                        (!checkObjOne && checkObjTwo)
                    ) {
                        return false;
                    }

                    if (!checkObjOne && !checkObjTwo) {
                        for (let i = 0; i <= obj1.length; i++) {
                            const compareIt = isObjSame(obj1[i], obj2[i]);
                            if (!compareIt) {
                                return false;
                            }
                        }

                        return true;
                    }

                    // if()
                }
                const newValue = isObjSame(obj1, obj2);
                return newValue;
            } else {
                return false;
            }
        }

        if (!Array.isArray(obj1) && !Array.isArray(obj2)) {
            let equal = true;
            if (obj1 && obj2) {
                const allKeys1 = Array.from(Object.keys(obj1));
                const allKeys2 = Array.from(Object.keys(obj2));

                if (allKeys1.length === allKeys2.length) {
                    allKeys1.sort((a, b) => a - b);
                    allKeys2.sort((a, b) => a - b);

                    allKeys1.map((key, index) => {
                        if (
                            key.toLowerCase() !== allKeys2[index].toLowerCase()
                        ) {
                            equal = false;
                            return;
                        }

                        const confirmEquality = isObjSame(obj1[key], obj2[key]);

                        if (!confirmEquality) {
                            equal = confirmEquality;
                            return;
                        }
                    });
                }
            }

            return equal;

            // return false;
        }
    }
};

如何确定部分对象(partial <T>)等于typescript中的原始对象(T)。

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

附注:最初我打算提出一个有答案的新问题。但这样的问题已经存在,并被标记为重复题。