严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
当前回答
简单来说:
const compare = (x, y) => {
const srt = (obj) => JSON.stringify(obj)?.split('').sort().join('');
return srt(x) === srt(y);
};
// ----- How to use ---
const a = {'one':1, 'two':2,'three':3};
const b = {'two':2, 'one':1, 'three':3}; //note same values as (const a)
const c = {'one':1, 'two':2,'three':3};
const d = {'one':1, 'two':2,'four':4};
compare(a, b); //true
compare(a, c); //true
compare(a, d); //false
//----- BUT! -----
JSON.stringify(a) === JSON.stringify(b); //false
//----- AND -----
compare({}, {}); //true
compare({}, undefined); //false
compare(undefined, undefined); //true
compare(undefined, ''); //false
compare(undefined, null); //false
compare(null, null); //true
compare('', ''); //true
其他回答
需要一个比已经发布的更通用的对象比较函数,我炮制了以下。批判赞赏……
Object.prototype.equals = function(iObj) {
if (this.constructor !== iObj.constructor)
return false;
var aMemberCount = 0;
for (var a in this) {
if (!this.hasOwnProperty(a))
continue;
if (typeof this[a] === 'object' && typeof iObj[a] === 'object' ? !this[a].equals(iObj[a]) : this[a] !== iObj[a])
return false;
++aMemberCount;
}
for (var a in iObj)
if (iObj.hasOwnProperty(a))
--aMemberCount;
return aMemberCount ? false : true;
}
我发现比较两个javascript对象的值而忽略属性顺序的一个简单方法是使用JSON stringify replacer函数:
const compareReplacer = (key, value) => {
if(typeof value === 'object' && !(value instanceof Array))
return Object.entries(value).sort();
return value;
}
export const compareObjects = (a, b) => JSON.stringify(a, compareReplacer) === JSON.stringify(b, compareReplacer);
这将在每一步对属性进行排序,以便字符串结果对属性顺序不变。以前可能有人这样做过,但我只是想分享一下,以防万一:)。
2022:
我想出了一个非常简单的算法来解决大多数边缘情况。
步骤:
使物体变平 简单地比较两个扁平的物体并寻找差异
如果你保存了平面对象,你可以重复使用它。
let obj1= {var1:'value1', var2:{ var1:'value1', var2:'value2'}};
let obj2 = {var1:'value1', var2:{ var1:'value11',var2:'value2'}}
let flat1= flattenObject(obj1)
/*
{
'var1':'value1',
'var2.var1':'value1',
'var2.var2':'value2'
}
*/
let flat2= flattenObject(obj2)
/*
{
'var1':'value1',
'var2.var1':'value11',
'var2.var2':'value2'
}
*/
isEqual(flat1, flat2)
/*
false
*/
当然,您可以为这些步骤提供您的实现。但我的想法是:
实现
function flattenObject(obj) {
const object = Object.create(null);
const path = [];
const isObject = (value) => Object(value) === value;
function dig(obj) {
for (let [key, value] of Object.entries(obj)) {
path.push(key);
if (isObject(value)) dig(value);
else object[path.join('.')] = value;
path.pop();
}
}
dig(obj);
return object;
}
function isEqual(flat1, flat2) {
for (let key in flat2) {
if (flat1[key] !== flat2[key])
return false
}
// check for missing keys
for (let key in flat1) {
if (!(key in flat2))
return false
}
return true
}
你也可以使用这个方法来获取obj1和obj2之间的Diff对象。
看看这个答案的细节:两个对象之间的一般深度差异
如果要比较JSON对象,可以使用https://github.com/mirek/node-rus-diff
npm install rus-diff
用法:
a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}
var rusDiff = require('rus-diff').rusDiff
console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }
如果两个对象不同,MongoDB兼容{$rename:{…},设置美元:{…},美元:{…返回}}like对象。
只是想利用一些es6的特性来贡献我的对象比较版本。它不考虑订单。在将所有if/else转换为三元后,我带来了以下内容:
function areEqual(obj1, obj2) {
return Object.keys(obj1).every(key => {
return obj2.hasOwnProperty(key) ?
typeof obj1[key] === 'object' ?
areEqual(obj1[key], obj2[key]) :
obj1[key] === obj2[key] :
false;
}
)
}