如何判断两个对象或者数组相同
起因
想写一个方法很长时间了,判断两个对象是否相同。
两个对象做对比,岂不简单:
obj1 === obj2
,, 不不不,不是判断是否是同一个对象。而是这样的:
1
2let obj1={} let obj2={}
判断两个对象的值是否相同,这样也有简单的方法:
1JSON.stringify(obj1) === JSON.stringify(obj2)
这样写确实很简单。把对象转化为字符串作比较。
发现问题
JSON.stringify
这样写还是有问题呀。
如果两个Object的key顺序不一样,会影响结果吗?举个例子:
1
2
3
4
5
6
7
8let obj1 = {} let obj2 = {} obj1.aVal=1 obj1.bVal=2 obj2.bVal=2 obj2.aVal=1
两个对象的赋值顺序不一样,结果如下:
1
2
3
4
5
6JSON.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
2let 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
42isSame(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 } }
这样的应用场景还是比较多的,目前已经应用到本站页面缓存,判断两个链接是否相同,参数是否相同。