深度克隆(深拷贝)一直都是初、中级前端面试中经常被问到的题目,网上介绍的实现方式也都各有千秋,大体可以概括为三种方式:
- JSON.stringify+JSON.parse, 这个很好理解;
- 全量判断类型,根据类型做不同的处理
- 2的变型,简化类型判断过程
第一种方法:
function deepClone(obj) {
let res = null;
const reference = [Date, RegExp, Set, WeakSet, Map, WeakMap, Error];
if (reference.includes(obj?.constructor)) {
res = new obj.constructor(obj);
} else if (Array.isArray(obj)) {
res = [];
obj.forEach((e, i) => {
res[i] = deepClone(e);
});
} else if (typeof obj === "Object" && obj !== null) {
res = {};
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
res[key] = deepClone(obj[key]);
}
}
} else {
res = obj;
}
return res;
}
第二种方法:
上面的方法还有循环引用问题,避免出现无线循环的问题。
我们用hash来存储已经加载过的对象,如果已经存在的对象,就直接返回。
function deepClone(obj, hash = new WeakMap()) {
if (hash.has(obj)) {
return obj;
}
let res = null;
const reference = [Date, RegExp, Set, WeakSet, Map, WeakMap, Error];
if (reference.includes(obj?.constructor)) {
res = new obj.constructor(obj);
} else if (Array.isArray(obj)) {
res = [];
obj.forEach((e, i) => {
res[i] = deepClone(e);
});
} else if (typeof obj === "Object" && obj !== null) {
res = {};
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
res[key] = deepClone(obj[key]);
}
}
} else {
res = obj;
}
hash.set(obj, res);
return res;
}