如何在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 代码片段。
无序比较
最后,有些情况下我们不关心数组中元素的顺序,只关心两个数组中是否存在相同的值。对于这种情况,你可以使用Set
和Array.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代码片段。