只有数组和对象的深克隆
deepClone方法
function deepClone(arr=undefined,spaceM=new Map()) {
if (typeof (arr) == "object") {
//区分递归中的arr是数组还是对象
//用展开运算符先浅克隆一波
let newArray = Array.isArray(arr) ? [...arr] : { ...arr };
//代码A部分开始,用Map阻止循环引用的克隆,防止栈溢出。
//其中key值保存的是arr,value值保存的是newArray,查看到map中已经有存储过的arr时,return终止进一步的for in循环
if (spaceM.get(arr)) {
return spaceM.get(arr);
}
spaceM.set(arr,newArray)
//代码A部分结束
for (const index in arr) {
if (typeof (arr[index]) == "object") {//发现有引用对象,进行递归deepClone克隆
newArray[index] = deepClone(arr[index],spaceM)
}
}
return newArray
} else {
return arr
}
}
Note
- 用展开运算符先浅克隆
- for in 循环查看浅克隆中的引用,通过递归再次克隆
- 在子递归中,新的newArray被return出来,即deepClone(arr[index], spaceM)会开辟一块新的空间,返回一个新的引用,赋值给newArray[index],这时深克隆完成
- 深克隆要考虑到克隆的对象存在循环引用情况,如A的next指向B,B的next指向A,通过Map阻止一直递归克隆。map最终的key是老的arr的各个引用节点,value则是新的arr的各个引用节点
测试
测试一
let space = new Map()
let arr = [
// {a:1,b:2},
2,
[1, 2, 3],
"fae"
]
let newArray = deepClone(arr, space)
console.log(newArray)
console.log(space)
测试二
let space = new Map()
let arr1 = {
a: 1,
b: 1,
d: {
a: 1,
b: 1
},
c: 1,
f: [
{ a: 1, b: 2 },
2,
[1, 2, 3],
"fae"
]
}
let newArray = deepClone(arr1, space)
console.log(newArray)
console.log(space)
测试三
let space = new Map()
let A = {}
let B = {}
A.next = B
A.x = 12
B.next = A
B.x = 13
let newArray = deepClone(A, space)
console.log(newArray)
console.log(space)