原文: JavaScript Comparison Operators – How to Compare Objects for Equality in JS

在用 JavaScript 编码的时候,可能有的时候你需要比较对象是否相等。问题是,在 JavaScript 中比较对象并不是那么容易的。

在这篇文章中,你会学到三种在 JavaScript 中比较对象是否相等的方法。

让我们开始学习吧!

比较 JavaScript 中的原始数据类型和非原始数据类型有什么区别

JavaScript 中的数据类型可分为两类:

  • 原始数据类型(如数字、字符串、布尔值、Undefined、Null、符号)
  • 非原始的数据(如对象)

原始数据类型指的是一个单一的值,比较原始值是相对简单的--你只需要使用任何一个比较运算符。

在下面的例子中,我使用了严格相等运算符,===,它检查两个操作数是否相等并返回一个布尔值作为结果:

let a = 1;
let b = 1;

console.log(a === b); // true

你也可以将变量 a 的值赋给另一个变量 a1,并将它们进行比较:

let a = 1;
let b = 1;

let a1 = a;

console.log(a === a1); // true

在上面的例子中,两个变量都指向同一个值,所以结果是 true

然而,当涉及到对象时,比较它们并不那么直接。

let a = { name: 'Dionysia', age: 29};
let b = {name: 'Dionysia', age:29};

console.log(a === b); // false

尽管两个对象都有相同的键值对,但比较的结果是 false。为什么会这样呢?

是不是因为我使用了严格相等运算符,===?如果我使用松散相等运算符 ==,会发生什么?

let a = { name: 'Dionysia', age: 29};
let b = {name: 'Dionysia', age:29};

console.log(a == b); // false

我得到了同样的结果!

ab 看起来都是一样的,然而当我使用 ===== 时,这些对象却不相等。

你会认为两个具有相同属性的对象和具有相同值的属性会被认为是相等的。

造成这种结果的原因与 JavaScript 在比较原始数据类型和非原始数据类型时如何进行相等测试有关。

原始数据类型和非原始数据类型的区别在于:

  • 原始数据类型是通过值进行比较的。
  • 非原始数据类型是通过引用来比较的。

在下面的章节中,你将看到一些比较对象是否相等的方法。

如何在 JavaScript 中通过引用来比较对象

正如你在上面一节的例子中看到的,当你试图通过值来比较对象时,使用 ===== 返回错误:

let a = { name: 'Dionysia', age: 29};
let b = {name: 'Dionysia', age:29};

console.log(a === b); // false

两个对象都有相同的键和值,但结果是 false,因为它们是不同的实例。

要通过引用来比较对象,你必须测试两者是否指向内存中的同一位置。

当引用一个对象时,你指的是内存中的一个地址。

让我们看一个例子:

let a = { name: 'Dionysia', age: 29};

let b = a;


console.log(a === b); // true

在上面的例子中,由于有 let b = a; 这一行,两个变量都有相同的引用,都指向同一个对象实例,所以结果是 true

当我把变量 a 赋值给 b 时,a 的地址被复制到 b,这导致两者都有相同的地址,而不是相同的值。

综上所述,在大多数情况下,你会想通过值而不是实例来比较对象。

正如你所看到的,你不能仅仅使用 ===== 来比较对象的值——这需要更多的工作。

如何在 JavaScript 中使用 JSON.stringify() 函数来比较对象

你可以通过使用 JSON.stringify 函数来比较两个对象的值。

JSON.stringify() 函数将对象转换为等价的 JSON 字符串。然后你可以使用任何一个比较运算符来比较字符串。

let a = { name: 'Dionysia', age: 29};
let b = { name: 'Dionysia', age: 29};

console.log(JSON.stringify(a) === JSON.stringify(b)); // true

JSON.stringify() 函数将两个对象都转换为 JSON 字符串,由于 ab 都有相同的属性和值,所以结果为 true

但是 JSON.stringify() 并不总是按值比较对象的最佳解决方案,因为它有局限性。

首先,当使用 JSON.stringify() 时,键的顺序很重要。

看看当键的顺序不同时会发生什么:

let a = { age: 29, name: 'Dionysia'};
let b = { name: 'Dionysia', age: 29};

console.log(JSON.stringify(a) === JSON.stringify(b)); //false

在这个例子中,你会期望结果是 true,因为值是一样的——只是键的顺序被颠倒了。

JSON.stringify() 将对象字符串化,所以键的顺序很重要。如果它们的顺序不一样,结果将是 false

所以,JSON.stringify() 不是比较对象的最佳选择,因为你不可能总是确定键的顺序。

还有一个额外的限制:JSON 并不代表所有类型。

看看当一个键的值是 undefined 的时候会发生什么:

let a = { name: 'Dionysia'};
let b = { name: 'Dionysia', age: undefined};

console.log(JSON.stringify(a) === JSON.stringify(b)); //true

在上面的例子中,结果是意外的。结果应该是 false,但却返回为 true,因为 JSON 忽略了那些未定义值的键。

如何在 JavaScript 中使用 Lodash .isEqual() 方法来比较对象

一个优雅而复杂的根据对象的值进行比较的解决方案是使用久经考验的 JavaScript 库 Lodash 和它的 .isEqual() 方法。

让我们来看看上一节的例子,其中的键具有相同的值,但顺序不同,并使用 _.isEqual() 方法:

let a = { age: 29, name: 'Dionysia'};
let b = { name: 'Dionysia', age: 29};

console.log(_.isEqual(a, b)); // true

在上一节中,使用 JSON.stringify 时的结果是 false

Lodash 库提供了各种边缘情况,并对两个值进行深度比较,以检查两个对象是否深度相等。

小结

在这篇文章中,你学到了如何在 JavaScript 中比较对象是否相等。

你看到了三种不同的方法以及每种方法的优点和缺点。当你有疑问时,最有效的方法是使用 Lodash 库来比较对象。

谢谢你阅读本文。