深浅合并 shallow/deep merge

参考

总结

  • 合并的两个参数类型不同会有不同的结果
    • 有且只有一个对象,会用对象作为最后结果(无论是第一个还是第二个)
    • 都不是对象,直接用第二个替换第一个
  • shallow 只处理第一层(类似 Object.assign() ),deep 会遍历处理

疑问

  • 如果其中有一个数组,是怎么处理的?

实现(来自 参考01 ):

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
function shallowMerge(obj1, obj2){
var isPlain1 = isPlainObject(obj1);
var isPlain2 = isPlainObject(obj2);
//只要obj1不是对象,那么不管obj2是不是对象,都用obj2直接替换obj1
if(!isPlain1) return obj2;
//走到这一步时,说明obj1肯定是对象,那如果obj2不是对象,则还是以obj1为主
if(!isPlain2) return obj1;
//如果上面两个条件都不成立,那说明obj1和obj2肯定都是对象, 则遍历obj2 进行合并
let keys = [
...Object.keys(obj2),
...Object.getOwnPropertySymbols(obj2)
]
keys.forEach(function(key){
obj1[key] = obj2[key];
});

return obj1;
}


function deepMerge(obj1, obj2, cache){
//防止死循环,这里需要把循环过的对象添加到数组中
cache = Array.isArray(cache) ? cache: [];
//因为后面只对obj2进行遍历,所以这里只要判断obj2就可以了,如果obj2已经比较合并过了则直接返回obj2,否则在继续合并
if(cache.indexOf(obj2)>-1) return obj2;
cache.push(obj2);

var isPlain1 = isPlainObject(obj1);
var isPlain2 = isPlainObject(obj2);
//obj1或obj2中只要其中一个不是对象,则按照浅合并的规则进行合并
if(!isPlain1 || !isPlain2) return shallowMerge(obj1, obj2);
//如果都是对象,则进行每一层级的递归合并
let keys = [
...Object.keys(obj2),
...Object.getOwnPropertySymbols(obj2)
]
keys.forEach(function(key){
obj1[key] = deepMerge(obj1[key], obj2[key], cache);//这里递归调用
});

return obj1;
}