严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
当前回答
我发现比较两个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);
这将在每一步对属性进行排序,以便字符串结果对属性顺序不变。以前可能有人这样做过,但我只是想分享一下,以防万一:)。
其他回答
如果要比较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对象。
这是一个经典的javascript问题!我创建了一个方法来检查深度对象是否相等,其特性是能够从比较中选择要忽略的属性。 参数是要比较的两个对象,加上一个可选的字符串化属性-忽略相对路径数组。
function isObjectEqual( o1, o2, ignorePropsArr=[]) {
// Deep Clone objects
let _obj1 = JSON.parse(JSON.stringify(o1)),
_obj2 = JSON.parse(JSON.stringify(o2));
// Remove props to ignore
ignorePropsArr.map( p => {
eval('_obj1.'+p+' = _obj2.'+p+' = "IGNORED"');
});
// compare as strings
let s1 = JSON.stringify(_obj1),
s2 = JSON.stringify(_obj2);
// return [s1==s2,s1,s2];
return s1==s2;
}
// Objects 0 and 1 are exact equals
obj0 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj1 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj2 = { price: 66544.12, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj3 = { price: 66544.13, RSIs: [0.000432334, 0.00046531], candles: {A: 541, B: 321, C: 4322}}
obj4 = { price: 66544.14, RSIs: [0.000432334, 0.00046530], candles: {A: 543, B: 321, C: 4322}}
isObjectEqual(obj0,obj1) // true
isObjectEqual(obj0,obj2) // false
isObjectEqual(obj0,obj2,['price']) // true
isObjectEqual(obj0,obj3,['price']) // false
isObjectEqual(obj0,obj3,['price','candles.A']) // true
isObjectEqual(obj0,obj4,['price','RSIs[1]']) // true
简短的回答
简单的答案是:不,没有一般的方法来确定一个对象等于另一个你所指的意义。例外情况是当您严格地认为一个对象是无类型的。
长话短说
这个概念是一个Equals方法,它比较一个对象的两个不同实例,以指示它们在值级别上是否相等。但是,定义Equals方法应该如何实现取决于具体的类型。对具有基本值的属性进行迭代比较可能还不够:对象可能包含与相等无关的属性。例如,
function MyClass(a, b)
{
var c;
this.getCLazy = function() {
if (c === undefined) c = a * b // imagine * is really expensive
return c;
}
}
在上面的例子中,c对于确定MyClass的任何两个实例是否相等并不重要,只有a和b是重要的。在某些情况下,c可能在不同实例之间有所不同,但在比较中并不显著。
注意,当成员本身也可能是某个类型的实例,并且每个实例都需要有确定相等的方法时,这个问题就会出现。
更复杂的是,在JavaScript中,数据和方法之间的区别是模糊的。
一个对象可以引用一个作为事件处理程序调用的方法,这可能不被认为是其“值状态”的一部分。然而,另一个对象很可能被分配一个执行重要计算的函数,从而使这个实例与其他实例不同,仅仅因为它引用了不同的函数。
如果一个对象的现有原型方法被另一个函数覆盖,该怎么办?它还能被认为与另一个相同的实例相等吗?这个问题只能在每种类型的具体情况下回答。
如前所述,异常将是一个严格的无类型对象。在这种情况下,唯一明智的选择是对每个成员进行迭代和递归比较。即使这样,人们也要问一个函数的“值”是什么?
如果使用JSON库,可以将每个对象编码为JSON,然后比较结果字符串是否相等。
var obj1={test:"value"};
var obj2={test:"value2"};
alert(JSON.encode(obj1)===JSON.encode(obj2));
注意:虽然这个答案在很多情况下都有效,但由于各种原因,一些人在评论中指出了它的问题。在几乎所有情况下,您都希望找到更健壮的解决方案。
我写了一个运行在Node.js和浏览器上的小库,叫做compare.js。它提供了常见的比较运算符,例如==,!=,>,>=,<,<=和所有JavaScript数据类型的标识符。
例如,你可以用
cmp.eq(obj1, obj2);
这将检查是否相等(使用深度相等的方法)。否则,如果你这样做
cmp.id(obj1, obj2);
它将通过引用进行比较,从而检查标识。 您还可以在对象上使用<和>,它们表示子集和超集。
Compare.js被近700个单元测试覆盖,因此它应该不会有太多的bug;-)。
你可以在https://github.com/goloroden/compare.js上免费找到它,它是MIT许可下的开源软件。