众所周知: 深拷贝的实现方案有很多 最简单的 莫过于 JSON.stringify 和 JSON.parse 要注意的是记得用 try catch
其次便是使用 lodash, Radash 的库等等
方案三就是自己手写一个 深拷贝
首先定义一下测试用例:
const obj = {
a: 1,
b: 'string',
c: null,
d: undefined,
e: new Date(),
f: Symbol(),
g: {
a: 2,
b: 'string-2',
c: null
},
h: function () { return 123; },
m: [1, 2, 3]
i: [1, 2, undefined, null, 'string']
j: [1, 2, {a: 3, b: 'string-3', c: null}]
}
// 外加循环引用
obj.obj = obj
首先,先不管特殊类型和循环引用
const deepClone = (obj) => {
if (!obj) return obj;
if (typeof obj != "object") return obj;
const targetObj = object.create(obj);
for(let cur in obj) {
targetObj[cur] = deepClone(obj[cur])
}
return targetObj;
}
现在我们来解决一下特殊类型的干扰
const deepClone = (obj) => {
if (!obj) return obj;
if (obj instanceof Date) return new Date(obj);
if (typeof obj != "object") return obj;
const targetObj = new obj.constructor();
for(let cur in obj) {
targetObj[cur] = deepClone(obj[cur])
}
return targetObj;
}
接下来通过 map 来限制循环引用,方案类似于记忆化 + 深搜剪枝
const deepClone = (obj, map = new WeakMap()) => {
if (!obj) return obj;
if (obj instanceof Date) return new Date(obj);
if (typeof obj != "object") return obj;
// 剪枝优化,防止无限递归爆栈
if (map.get(obj)) return map.get(obj);
const targetObj = new obj.constructor();
map.set(obj, targetObj);
for(let cur in obj) {
if(obj.hasOwnProperty(key)) {
targetObj[cur] = deepClone(obj[cur])
}
}
return targetObj;
}