严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
当前回答
我的版本,包括发现差异的地方,以及差异是什么。
function DeepObjectCompare(O1, O2)
{
try {
DOC_Val(O1, O2, ['O1->O2', O1, O2]);
return DOC_Val(O2, O1, ['O2->O1', O1, O2]);
} catch(e) {
console.log(e.Chain);
throw(e);
}
}
function DOC_Error(Reason, Chain, Val1, Val2)
{
this.Reason=Reason;
this.Chain=Chain;
this.Val1=Val1;
this.Val2=Val2;
}
function DOC_Val(Val1, Val2, Chain)
{
function DoThrow(Reason, NewChain) { throw(new DOC_Error(Reason, NewChain!==undefined ? NewChain : Chain, Val1, Val2)); }
if(typeof(Val1)!==typeof(Val2))
return DoThrow('Type Mismatch');
if(Val1===null || Val1===undefined)
return Val1!==Val2 ? DoThrow('Null/undefined mismatch') : true;
if(Val1.constructor!==Val2.constructor)
return DoThrow('Constructor mismatch');
switch(typeof(Val1))
{
case 'object':
for(var m in Val1)
{
if(!Val1.hasOwnProperty(m))
continue;
var CurChain=Chain.concat([m]);
if(!Val2.hasOwnProperty(m))
return DoThrow('Val2 missing property', CurChain);
DOC_Val(Val1[m], Val2[m], CurChain);
}
return true;
case 'number':
if(Number.isNaN(Val1))
return !Number.isNaN(Val2) ? DoThrow('NaN mismatch') : true;
case 'string':
case 'boolean':
return Val1!==Val2 ? DoThrow('Value mismatch') : true;
case 'function':
if(Val1.prototype!==Val2.prototype)
return DoThrow('Prototype mismatch');
if(Val1!==Val2)
return DoThrow('Function mismatch');
return true;
default:
return DoThrow('Val1 is unknown type');
}
}
其他回答
我之前添加了一个答案,但它不是完美的,但这个将检查对象的相等性
function equalObjects(myObj1, myObj2){ let firstScore = 0; let secondScore = 0; let index=0; let proprtiesArray = []; let valuesArray = []; let firstLength = 0; let secondLength = 0; for (const key in myObj1) { if (myObj1.hasOwnProperty(key)) { firstLength += 1; proprtiesArray.push(key); valuesArray.push(myObj1[key]); firstScore +=1; } } for (const key in myObj2) { if (myObj2.hasOwnProperty(key)) { secondLength += 1; if (valuesArray[index] === myObj2[key] && proprtiesArray[index] === key) { secondScore +=1; } //console.log(myObj[key]); index += 1; } } if (secondScore == firstScore && firstLength === secondLength) { console.log("true", "equal objects"); return true; } else { console.log("false", "not equal objects"); return false; } } equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName':'Lovelace'}); equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName1':'Lovelace'}); equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName':'Lovelace', 'missing': false});
在JavaScript for Objects中,当它们引用内存中的相同位置时,默认的相等运算符将产生true。
var x = {};
var y = {};
var z = x;
x === y; // => false
x === z; // => true
如果你需要一个不同的相等操作符,你需要添加一个equals(other)方法,或者类似的东西到你的类中,你的问题领域的细节将决定它的确切含义。
这里有一个扑克牌的例子:
function Card(rank, suit) {
this.rank = rank;
this.suit = suit;
this.equals = function(other) {
return other.rank == this.rank && other.suit == this.suit;
};
}
var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");
queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true
我建议不要使用散列或序列化(正如JSON解决方案所建议的那样)。如果需要测试两个对象是否相等,则需要定义相等的含义。这可能是两个对象中的所有数据成员都匹配,也可能是内存位置必须匹配(意味着两个变量在内存中引用同一个对象),或者每个对象中只有一个数据成员必须匹配。
最近我开发了一个对象,它的构造函数在每次创建实例时都会创建一个新的id(从1开始,加1)。该对象有一个isEqual函数,用于将该id值与另一个对象的id值进行比较,如果匹配则返回true。
在这种情况下,我定义“相等”的意思是id值匹配。假设每个实例都有一个唯一的id,这可以用来加强匹配对象也占用相同内存位置的想法。尽管这是不必要的。
我对这个函数做如下假设:
你控制你比较的对象,你只有基本的值(例如。而不是嵌套的对象、函数等)。 您的浏览器支持Object.keys。
这应该被视为一个简单策略的示范。
/**
* Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.)
* @param {Object} object1
* @param {Object} object2
* @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}).
* @returns {Boolean}
*/
function isEqual( object1, object2, order_matters ) {
var keys1 = Object.keys(object1),
keys2 = Object.keys(object2),
i, key;
// Test 1: Same number of elements
if( keys1.length != keys2.length ) {
return false;
}
// If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true.
// keys1 = Object.keys({a:2, b:1}) = ["a","b"];
// keys2 = Object.keys({b:1, a:2}) = ["b","a"];
// This is why we are sorting keys1 and keys2.
if( !order_matters ) {
keys1.sort();
keys2.sort();
}
// Test 2: Same keys
for( i = 0; i < keys1.length; i++ ) {
if( keys1[i] != keys2[i] ) {
return false;
}
}
// Test 3: Values
for( i = 0; i < keys1.length; i++ ) {
key = keys1[i];
if( object1[key] != object2[key] ) {
return false;
}
}
return true;
}
如果要比较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对象。