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

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


当前回答

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

其他回答

虽然这个问题已经得到了充分的回答,但我还缺少一种方法:toJSON接口。

通常你想通过字符串化来比较object,因为这是最快的方法。但往往比较被认为是假的,因为性质的顺序。

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

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

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

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

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

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

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

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

瞧:obj1和obj2的字符串表示被认为是相同的。

TIP

如果你没有直接生成对象的权限,你可以简单地附加toJSON函数:

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

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

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

你可以使用_。isEqual(obj1, obj2)来自underscore.js库。

这里有一个例子:

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

在这里查看官方文档:http://underscorejs.org/#isEqual

最简单和逻辑的解决方案,比较一切像对象,数组,字符串,Int…

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

注意:

你需要用你的Object替换val1和val2 对于对象,必须对两侧对象进行递归排序(按键)

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

或者只使用这个包使用的代码

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

只是不要把它转换成字符串进行比较。

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

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.