1.使用JSON.parse/stringify
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
return JSON.parse(JSON.stringify(obj));
}
这种方式虽然简单,但是会存在以下问题
- 无法拷贝函数
- 对象中存在循环引用,则会报错
2.使用MessageChannel
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return Promise.resolve(obj);
}
return new Promise((resolve) => {
const { port1, port2 } = new MessageChannel();
port2.onmessage = (e) => resolve(e.data);
port1.postMessage(obj);
});
}
这种方式也会存在一些问题
- 拷贝函数会报错
- 只能通过异步的方式调用
3.自己封装实现
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
const res = Array.isArray(obj) ? [] : {};
for (const key in obj) {
res[key] = deepClone(obj[key]);
}
return res;
}
以上封装还是无法解决对象循环引用报错的问题,下面我们新增一个Map来存储已经复制过的对象,存在则直接终止递归。
function deepClone(obj) {
const copied = new WeakMap();
const _clone = (_obj) => {
if (_obj === null || typeof _obj !== "object") {
return _obj;
}
if (copied.has(_obj)) {
return _obj;
}
copied.set(_obj, true);
const res = Array.isArray(_obj) ? [] : {};
for (const key in _obj) {
res[key] = _clone(_obj[key]);
}
return res;
};
return _clone(obj);
}