协慌网

登录 贡献 社区

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

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

堆栈溢出问题JavaScript 中是否存在某种 hashCode 函数?与这个问题相似,但需要更多的学术答案。上面的场景演示了为什么必须要有一个,而我想知道是否有任何等效的解决方案

答案

为什么要重新发明轮子?试试Lodash。它具有许多必备功能,例如isEqual()

_.isEqual(object, other);

就像本页中的其他示例一样,它将使用ECMAScript 5和本机优化(如果浏览器中可用)蛮力检查每个键值。

注:以前这个答案推荐Underscore.js ,但lodash做得越来越修复的错误,并与一致性解决问题的一个更好的工作。

简短的答案

简单的答案是:不,就您的意思而言,没有通用的方法可以确定一个对象与另一个对象相等。例外是,当您严格考虑对象是无类型的时。

长答案

该概念是 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 的任何两个实例是否相等ab是重要的。在某些情况下, c在各个实例之间可能有所不同,但在比较过程中并不重要。

请注意,当成员本身也可能是类型的实例,并且每个成员都必须具有确定相等性的方法时,就会出现此问题。

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

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

如果某个对象的现有原型方法之一被另一个函数覆盖,那该怎么办?还是可以认为它等同于另一个实例,但在其他方面相同吗?对于每种类型,只能在每种特定情况下回答该问题。

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

当 JavaScript for Objects 引用内存中的相同位置时,其默认相等运算符将产生 true。

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

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

如果您需要其他相等运算符,则需要在类中添加一个equals(other)方法或类似的方法,而问题域的具体内容将确定这到底意味着什么。

这是一个纸牌示例:

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