Skip to content

如何在JavaScript中比较两个数组?

相等比较

在JavaScript中使用宽松相等运算符(==)或严格相等运算符(===)比较两个数组,即使这两个数组以相同的顺序包含相同的元素,结果通常也是false。这是因为在JavaScript中,数组和对象是通过引用而不是值进行比较的,这意味着这种解决方案无法产生期望的结果:

const a = [1, 2, 3];
const b = [1, 2, 3];

a === b; // false

JSON.stringify

许多人建议的常见解决方案是使用JSON.stringify()。这允许我们将每个数组序列化,然后比较两个序列化的字符串。一个简单的实现可能如下所示:

const equals = (a, b) => JSON.stringify(a) === JSON.stringify(b);

const a = [1, 2, 3];
const b = [1, 2, 3];

equals(a, b); // true

虽然这个解决方案看起来很好,简短且易于理解,但在一些边缘情况下存在问题,其中不同值的序列化字符串相同。例如:

const str = 'a';
const strObj = new String('a');
str === strObj; // false
equals([str], [strObj]); // true,应该是 false

null === undefined; // false
equals([null], [undefined]); // true,应该是 false

虽然这些情况似乎很少见,但它们可能会导致一些非常烦人的问题,很难追踪和修复。这就是为什么这个解决方案不推荐用于大多数用例的原因。

更好的方法

一个更好的方法是比较两个数组的 length,并使用 Array.prototype.every() 来比较两个数组的值:

const equals = (a, b) =>
  a.length === b.length &&
  a.every((v, i) => v === b[i]);

const a = [1, 2, 3];
const b = [1, 2, 3];
const str = 'a';
const strObj = new String('a');

equals(a, b); // true
equals([str], [strObj]); // false
equals([null], [undefined]); // false

这种方法可以防止上述描述的序列化问题。然而,它不考虑嵌套的数组或对象,需要递归地进行检查。对于处理这个和其他问题的健壮解决方案,你应该使用 equals 代码片段

无序比较

最后,有些情况下我们不关心数组中元素的顺序,只关心两个数组中是否存在相同的值。对于这种情况,你可以使用SetArray.prototype.filter()结合循环来遍历唯一的值,并检查每个值在两个数组中出现的次数是否相同:

const equalsIgnoreOrder = (a, b) => {
  if (a.length !== b.length) return false;
  const uniqueValues = new Set([...a, ...b]);
  for (const v of uniqueValues) {
    const aCount = a.filter(e => e === v).length;
    const bCount = b.filter(e => e === v).length;
    if (aCount !== bCount) return false;
  }
  return true;
}

如果你想要更详细的解释,可以查看haveSameContents代码片段