严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?
堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。
当前回答
如果两个对象的所有属性都具有相同的值,并且所有嵌套对象和数组都递归地具有相同的值,那么将它们视为相等是很有用的。我也认为以下两个对象是相等的:
var a = {p1: 1};
var b = {p1: 1, p2: undefined};
类似地,数组可以有“缺失”元素和未定义的元素。我也会同样对待它们:
var c = [1, 2];
var d = [1, 2, undefined];
函数:实现等式定义的函数:
function isEqual(a, b) {
if (a === b) {
return true;
}
if (generalType(a) != generalType(b)) {
return false;
}
if (a == b) {
return true;
}
if (typeof a != 'object') {
return false;
}
// null != {}
if (a instanceof Object != b instanceof Object) {
return false;
}
if (a instanceof Date || b instanceof Date) {
if (a instanceof Date != b instanceof Date ||
a.getTime() != b.getTime()) {
return false;
}
}
var allKeys = [].concat(keys(a), keys(b));
uniqueArray(allKeys);
for (var i = 0; i < allKeys.length; i++) {
var prop = allKeys[i];
if (!isEqual(a[prop], b[prop])) {
return false;
}
}
return true;
}
源代码(包括辅助函数,generalType和uniqueArray): 这里是单元测试和测试运行器。
其他回答
下面是一个使用ES6+的解决方案
// this comparison would not work for function and symbol comparisons
// this would only work best for compared objects that do not belong to same address in memory
// Returns true if there is no difference, and false otherwise
export const isObjSame = (obj1, obj2) => {
if (typeof obj1 !== "object" && obj1 !== obj2) {
return false;
}
if (typeof obj1 !== "object" && typeof obj2 !== "object" && obj1 === obj2) {
return true;
}
if (typeof obj1 === "object" && typeof obj2 === "object") {
if (Array.isArray(obj1) && Array.isArray(obj2)) {
if (obj1.length === obj2.length) {
if (obj1.length === 0) {
return true;
}
const firstElemType = typeof obj1[0];
if (typeof firstElemType !== "object") {
const confirmSameType = currentType =>
typeof currentType === firstElemType;
const checkObjOne = obj1.every(confirmSameType);
const checkObjTwo = obj2.every(confirmSameType);
if (checkObjOne && checkObjTwo) {
// they are primitves, we can therefore sort before and compare by index
// use number sort
// use alphabet sort
// use regular sort
if (firstElemType === "string") {
obj1.sort((a, b) => a.localeCompare(b));
obj2.sort((a, b) => a.localeCompare(b));
}
obj1.sort((a, b) => a - b);
obj2.sort((a, b) => a - b);
let equal = true;
obj1.map((element, index) => {
if (!isObjSame(element, obj2[index])) {
equal = false;
}
});
return equal;
}
if (
(checkObjOne && !checkObjTwo) ||
(!checkObjOne && checkObjTwo)
) {
return false;
}
if (!checkObjOne && !checkObjTwo) {
for (let i = 0; i <= obj1.length; i++) {
const compareIt = isObjSame(obj1[i], obj2[i]);
if (!compareIt) {
return false;
}
}
return true;
}
// if()
}
const newValue = isObjSame(obj1, obj2);
return newValue;
} else {
return false;
}
}
if (!Array.isArray(obj1) && !Array.isArray(obj2)) {
let equal = true;
if (obj1 && obj2) {
const allKeys1 = Array.from(Object.keys(obj1));
const allKeys2 = Array.from(Object.keys(obj2));
if (allKeys1.length === allKeys2.length) {
allKeys1.sort((a, b) => a - b);
allKeys2.sort((a, b) => a - b);
allKeys1.map((key, index) => {
if (
key.toLowerCase() !== allKeys2[index].toLowerCase()
) {
equal = false;
return;
}
const confirmEquality = isObjSame(obj1[key], obj2[key]);
if (!confirmEquality) {
equal = confirmEquality;
return;
}
});
}
}
return equal;
// return false;
}
}
};
如果使用JSON库,可以将每个对象编码为JSON,然后比较结果字符串是否相等。
var obj1={test:"value"};
var obj2={test:"value2"};
alert(JSON.encode(obj1)===JSON.encode(obj2));
注意:虽然这个答案在很多情况下都有效,但由于各种原因,一些人在评论中指出了它的问题。在几乎所有情况下,您都希望找到更健壮的解决方案。
简短的回答
简单的答案是:不,没有一般的方法来确定一个对象等于另一个你所指的意义。例外情况是当您严格地认为一个对象是无类型的。
长话短说
这个概念是一个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中,数据和方法之间的区别是模糊的。
一个对象可以引用一个作为事件处理程序调用的方法,这可能不被认为是其“值状态”的一部分。然而,另一个对象很可能被分配一个执行重要计算的函数,从而使这个实例与其他实例不同,仅仅因为它引用了不同的函数。
如果一个对象的现有原型方法被另一个函数覆盖,该怎么办?它还能被认为与另一个相同的实例相等吗?这个问题只能在每种类型的具体情况下回答。
如前所述,异常将是一个严格的无类型对象。在这种情况下,唯一明智的选择是对每个成员进行迭代和递归比较。即使这样,人们也要问一个函数的“值”是什么?
let user1 = { name: "John", address: { line1: "55 Green Park Road", line2: { a:[1,2,3] } }, email:null } let user2 = { name: "John", address: { line1: "55 Green Park Road", line2: { a:[1,2,3] } }, email:null } // Method 1 function isEqual(a, b) { return JSON.stringify(a) === JSON.stringify(b); } // Method 2 function isEqual(a, b) { // checking type of a And b if(typeof a !== 'object' || typeof b !== 'object') { return false; } // Both are NULL if(!a && !b ) { return true; } else if(!a || !b) { return false; } let keysA = Object.keys(a); let keysB = Object.keys(b); if(keysA.length !== keysB.length) { return false; } for(let key in a) { if(!(key in b)) { return false; } if(typeof a[key] === 'object') { if(!isEqual(a[key], b[key])) { return false; } } else { if(a[key] !== b[key]) { return false; } } } return true; } console.log(isEqual(user1,user2));
最简单和逻辑的解决方案,比较一切像对象,数组,字符串,Int…
JSON。stringify({a: val1}) == JSON。stringify ({a: val2})
注意:
你需要用你的Object替换val1和val2 对于对象,必须对两侧对象进行递归排序(按键)