0%

实现深度克隆/拷贝,解决循环引用

基础版(不能解决循环引用)
基础版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function deepClone(obj){
// 如果参数为空则直接返回,如果为日期/正则 则也直接返回;
if( obj == null ) return obj;
if( obj instanceof Date ) return new Date(obj);
if( obj instanceof RegExp ) return new RegExp(obj);
if(typeof obj !== 'object') return obj;
let cloneObj = new obj.constructor; // 此时是为了获取 obj 的类型, 并且可以根据类型来新建相应的拷贝对象;
// 根据上文的对象类型,来进行填充;
for(let key in obj){
if(obj.hasOwnProperty(key)){ // 过滤掉对象元属性上面的属性;
cloneObj[key] = deepClone(obj[key])
}
}
return cloneObj;
}

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
let od = {
name: '张三',
age: 18,
address: {
province: '上海市',
district: '浦东新区'
},
dateVal: dateVal: new Date('2020-02-14').toLocaleString(),
re:new RegExp()
}
var cloneData = deepClone(od);
console.log(cloneData);
// cloneData 输出如下 {address:{province:"上海市",district:"浦东新区"},age:18,dateVal:"2020/2/14 上午8:00:00",name:"张三",re:/(?:)/,}

如果循环引用到导致爆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 如果循环引用 会直接导致爆栈;
let od = {
name: '张三',
age: 18,
address: {
province: '上海市',
district: '浦东新区'
},
dateVal: dateVal: new Date('2020-02-14').toLocaleString(),
re:new RegExp()
}
od.cloneSelf = cloneData
var cloneData = deepClone(od);
// VM6546:5 Uncaught RangeError: Maximum call stack size exceeded

内存栈溢出
增强版(兼容循环引用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 该函数的关键点为 WeakMap, 主要是为了解决循环引用问题;
function deepClone(obj,hash = new WeakMap()){
// 如果参数为空则直接返回,如果为日期/正则 则也直接返回;
if( obj == null ) return obj;
if( obj instanceof Date ) return new Date(obj);
if( obj instanceof RegExp ) return new RegExp(obj);
if(typeof obj !== 'object') return obj;
if(hash.has(obj)) return hash.get(obj); // 如果weakmap 中存在则直接返回; 解决 参数本身引用本身造成爆栈;
let cloneObj = new obj.constructor; // 此时是为了获取 obj 的类型, 并且可以根据类型来新建相应的拷贝对象;

hash.set(obj, cloneObj); // 将 obj 设置为对象则将对象放入 WeakMap 中, 拷贝的时候如果没有该值则直接从weakMap 中取就好了;

// 根据上文的对象类型,来进行填充;
for(let key in obj){
if(obj.hasOwnProperty(key)){ // 过滤掉对象元属性上面的属相
cloneObj[key] = deepClone(obj[key], hash)
}
}
return cloneObj;
}

此时循环引用则正常输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 如果循环引用 会直接导致爆栈;
let od = {
name: '张三',
age: 18,
address: {
province: '上海市',
district: '浦东新区'
},
dateVal: dateVal: new Date('2020-02-14').toLocaleString(),
re:new RegExp()
}
od.cloneSelf = cloneData
var cloneData = deepClone(od);
// 输出如下
// { address:{province:"上海市",district:"浦东新区"},age:18,dateVal:"2020/2/14 上午8:00:00",name:"张三",re:/(?:)/, cloneSelf : [Circular] }

cloneSelf 属性为一个循环嵌套属性;
循环嵌套

------ 本文结束------