typescript - 比较两个对象数组是否相等,而不考虑对象属性的顺序
我正在尝试比较两个对象数组是否相等,忽略属性顺序的任何差异。我只想知道每个属性的值是否匹配。下面是每个数组中一个对象的示例,根据每个属性的值,这些对象应该是相等的。属性的顺序无关紧要,“values”属性值的顺序也无关紧要。
{ "fieldId": "123456789",
"operationType": 1,
"definitionType": 1,
"values": ["123","456"],
"isAllSelected": false,
"dateRangeSelectionType": 0
}
{ "isAllSelected": false,
"operationType": 1,
"definitionType": 1,
"fieldId": "123456789",
"values": ["456","123"],
"dateRangeSelectionType": 0
}
我尝试过使用 JSON.stringify 来比较这些数组,但我知道这行不通,因为它会将顺序考虑进相等性。
我还有以下辅助函数,我正在将它们用于另一个对象数组,但它们对这些数组不起作用:
> const objectsAreEqual = (object1: any, object2: any) =>
> Object.keys(object1).length === Object.keys(object2).length
> && Object.keys(object1).every(index => object1[index] === object2[index]);
>
> const objectArraysAreEqual = (array1: Object[], array2: Object[]) =>
> array1.length === array2.length && array1.every((x, index) => objectsAreEqual(x, array2[index]));
答案#1
首先,请注意我整理了一下数据。在你的第二个示例对象中,"isAllSelected": false, 出现了两次,这不是一个有效的 JavaScript 对象。此外,values 数组的元素顺序被交换了,这实际上使它们 不是 同一个对象,所以在这些演示示例中,我将它们都设为完全相同的数组。
既然你把这个标记为 TypeScript 问题,我首先为这个对象的结构创建了一个 TypeScript 类型,我将其命名为“Foo”。
type Foo = {
fieldId: string;
operationType: number;
definitionType: number;
values: string[];
isAllSelected: boolean,
dateRangeSelectionType: number
}
然后我将这两个对象定义为 Foo 类型。
const fooA: Foo = {
"fieldId": "123456789",
"operationType": 1,
"definitionType": 1,
"values": ["123","456"],
"isAllSelected": false,
"dateRangeSelectionType": 0
}
const fooB: Foo = {
"isAllSelected": false,
"operationType": 1,
"definitionType": 1,
"fieldId": "123456789",
"values": ["123", "456"],
"dateRangeSelectionType": 0
}
对于原始类型来说,使用 == 和 === 运算符是好的,但在比较这些对象时,它们会返回“false”,Object.is 函数也是如此。
console.log(fooA == fooB) // false
console.log(fooA === fooB) // false
console.log(Object.is(fooA, fooB)) // false
所以,看起来你将不得不挽起袖子,检查对象中的每一个键和值...
你基本上想做的是:
确保对象具有相同的键。
确保这些键具有相同的值。
棘手的部分是如果值本身是对象,会发生什么?在某些情况下,你可能只想进行浅层相等比较(例如,如果你希望你的函数在“values”数组有不同元素时仍然认为它们是相等的)。
如果你希望该函数继续深入检查对象中的所有内容是否都相同,那么你需要检查“深度相等”。
这是你可以实现此功能的一种实现方式:
export default function deepEquals(object1: any, object2: any) {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
const val1 = object1[key];
const val2 = object2[key];
const areObjects = isObject(val1) && isObject(val2);
if (
areObjects && !deepEquals(val1, val2) ||
!areObjects && val1 !== val2
) {
return false;
}
}
return true;
}
function isObject(object: Object) {
return object != null && typeof object === 'object';
}
注意当比较这些对象时,这个函数返回 true:
import deepEquals from './deepEquals';
console.log(deepEquals(fooA, fooB)) // true
你也可以使用像 lodash 这样的库,它具有深度对象比较功能:
import isEqual from 'lodash.isequal';
console.log(isEqual(fooA, fooB)) // true
答案#2
你可以这样使用函数
function deepEqual(obj1: object, obj2: object): boolean {
if (obj1 === obj2) {
return true;
}
if (typeof obj1 !== 'object' || obj1 === null ||
typeof obj2 !== 'object' || obj2 === null) {
return false;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (!obj2.hasOwnProperty(key)) {
return false;
}
if (!deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}或者使用 lodash 函数,请参考这篇文章 https://bytesinsights.dev/blog/comparing-two-deep-objects-in-typescript-a-comprehensive-guide-with-examples
