起因
想写一个方法很长时间了,判断两个对象是否相同。
两个对象做对比,岂不简单:
obj1 === obj2
,, 不不不,不是判断是否是同一个对象。而是这样的:
1
2
let obj1={}
let obj2={}
判断两个对象的值是否相同,这样也有简单的方法:
1
JSON.stringify(obj1) === JSON.stringify(obj2)
这样写确实很简单。把对象转化为字符串作比较。
也会有问题
JSON.stringify
这样写还是有问题呀。
如果两个Object的key顺序不一样,会影响结果吗?举个例子:
1
2
3
4
5
6
7
8
let obj1 = {}
let obj2 = {}
obj1.aVal=1
obj1.bVal=2
obj2.bVal=2
obj2.aVal=1
两个对象的赋值顺序不一样,结果如下:
1
2
3
4
5
6
JSON.stringify(obj1)
'{"aVal":1,"bVal":2}'
JSON.stringify(obj2)
'{"bVal":2,"aVal":1}'
JSON.stringify(obj2) === JSON.stringify(obj1)
false
和想象中的一样,这样写会有bug的。
通过递归判断对象是否相同
手写一个通用的判断?
思考片刻,通过递归判断对象是否相同如何?之前写过深度clone一个对象的方法,思路应该差不多呀。
实践过程确实有点复杂。不仅判断了Object,Array的也需要考虑。
有Array的情况
1
2
let obj1={arr: [1,2]}
let obj2={arr: [2,1]}
这样两个对象的值应不应该相同呢,因为我的业务需求,这种情况要求 obj1==obj2
就不卖关子了,解决方案如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
isSame(val1,val2){
if(this.isArray(val1) && this.isArray(val2)){
if(val1.length!==val2.length){
return false
}
return val1.every(value=>val2.some(v=>this.isSame(value, v)))
}else if(this.isObject(val1) && this.isObject(val2)){
let keys1=Object.keys(val1), keys2=Object.keys(val2)
if(keys1.length!==keys2.length){
return false
}
for(let i=0,len=keys1.length; i<len; i++){
if(!this.isSame(val1[keys1[i]], val2[keys1[i]])){
return false
}
}
return true
}else if(this.isMap(val1) && this.isMap(val2)){
if(val1.size !== val2.size){
return false
}
let keys = val1.keys()
for(let i=0,len=val1.size; i<len; i++){
let key = keys.next().value
if(!this.isSame(val1.get(key),val2.get(key))){
return false
}
}
return true
}else if(this.isSet(val1) && this.isSet(val2)){
if(val1.size !== val2.size){
return false
}
return this.isSame(Array.from(val1),Array.from(val2))
}else if(this.isDate(val1) && this.isDate(val2)){
return val1.getTime() == val2.getTime()
}else if(val1===val2){
return true
}else{
return false
}
}
这样的应用场景还是比较多的,目前已经应用到本站页面缓存,判断两个链接是否相同,参数是否相同。