背景
对象的比较使用==和===比较,即使拥有相同的属性和相同的值,但很有可能不相等的。这是因为它们是通过它们的引用来比较的(也就是在内存中的地址)。所以就需要通过比较对象自身的属性。
分析
1.如果比较的两个对象===,返回true。
let obj = {
id: 1213,
name: "张三"
};
let obj2 =obj;
console.log(obj === obj); //true
console.log(obj === obj2); //true
2.如果比较的是两个方法,转成字符串比较
toString()和valueOf()又不太了解的可以阅读这篇文章
let fun1 = function(param) {
console.log(arguments);
};
let fun3 = function(param) {
console.log(arguments);
};
console.log(fun1 == fun3); //false
console.log(fun1.toString() == fun3.toString()); //true
3.如果比较的是两个是Date对象,直接获取毫秒值比较
let mDate1 = new Date();
let mDate2 = new Date();
console.log(mDate1.getTime() === mDate2.getTime());//true
2.判断完上面的特殊情况,比较是两个 对象 类型不一致
let obj1=123;
let obj2='123';
let obj3='abc';
console.log(Object.prototype.toString.call(obj1));//[object Number]
console.log(Object.prototype.toString.call(obj2));//[object String]
console.log(Object.prototype.toString.call(obj1)===Object.prototype.toString.call(obj2));//false
console.log(Object.prototype.toString.call(obj2)===Object.prototype.toString.call(obj3));//true
5.两个对象开始比较自身属性(包括长度)
let obj1 = {
id: 1213,
name: "张三"
};
let obj2 = {
id: 1213,
name: "张三"
};
//获取对象所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)
const obj1Props = Object.getOwnPropertyNames(obj1);
const obj2Props = Object.getOwnPropertyNames(obj2);
console.log(obj1Props.length === obj2Props.length );
console.table(obj1Props);
console.table(obj2Props);
这样就可以遍历属性的值是否相同。
总结
结合上面的几种情况,就可以写出一个判断对象是否相等的方法(相等指的是属性和属性值相等,不去深究其原型是否相等)
function isDeepObjectEqual(obj1, obj2) {
//1.如果是比较对象===,返回true
if (obj1 === obj2) return true;
//2.如果比较的是两个方法,转成字符串比较
if (typeof obj1 === "function" && typeof obj2 === "function") return obj1.toString() === obj2.toString();
//3如果obj1和obj2都是Date实例,获取毫秒值比较
if (obj1 instanceof Date && obj2 instanceof Date) return obj1.getTime() === obj2.getTime();
//4如果比较是两个类型不一致,无须比较直接返回false
if ( Object.prototype.toString.call(obj1) !==Object.prototype.toString.call(obj2) || typeof obj1 !== "object") return false;
//5.获取对象所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性
const obj1Props = Object.getOwnPropertyNames(obj1);
const obj2Props = Object.getOwnPropertyNames(obj2);
//自身属性长度相等,
if(obj1Props.length !== obj2Props.length) return false;
//递归调用判断每一个属性值是否相等
return (obj1Props.every(prop => isDeepObjectEqual(obj1[prop], obj2[prop])));
}
下面测试一下(上面的判断顺序得注意了,由于要使用递归,还有就是判断一些他特殊对象,最好先判断特殊对象,在按照一般对象比较属性)
let obj1 ='123';
let obj2 ='abc';
let obj3={
id:10001,
name:'ShangSan'
};
let obj4={
id:10001,
name:'ShangSan'
};
let obj5={
id:10001,
name:'ShangSan',
address:'Beijing'
};
let fun1 = function(param) {
console.log(arguments);
};
let fun3 = function(param) {
console.log(arguments);
};
let mDate1 = new Date();
let mDate2 = new Date();
console.log(isDeepObjectEqual(obj1, obj1));//true
console.log(isDeepObjectEqual(fun1, fun3));//true
console.log(isDeepObjectEqual(mDate1, mDate2));//true
console.log(isDeepObjectEqual(obj1, obj2));//false
console.log(isDeepObjectEqual(obj3, obj4));//true
console.log(isDeepObjectEqual(obj3, obj5));//false
//比较个复杂的
let mObjB={
id:1001,
name:'abc',
isChinese:true,
work:function(){
console.log(arguments);
}
};
let mObjA={
id:1001,
name:'abc',
isChinese:true,
work:function(){
console.log(arguments);
}
};
console.log(isDeepObjectEqual(mObjB, mObjA));//true
提醒
当然要是严谨,还可以比较两个对象的原型
console.log(Object.getPrototypeOf(obj1)==Object.getPrototypeOf(obj2));//true
甚至可以把两个对象的原型的属性在进行比较。(这里就不展开了~~~)
利用上面的方法
const prototypesAreEqual = isDeepEqual(Object.getPrototypeOf(obj1),Object.getPrototypeOf(obj2))








网友评论