一般对象的深拷贝实现
function deepCopy(obj, cache = []) {
function find(list, f) {
return list.filter(f)[0];
}
// 如果是简单数据类型,直接返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
const hit = find(cache, (c) => c.original === obj);
// 如果有循环引用,直接返回
if (hit) {
return hit.copy;
}
const copy = Array.isArray(obj) ? [] : {};
// 先把 copy 放到cache缓存中,我们想在递归的时候引用它
cache.push({original: obj, copy});
Object.keys(obj).forEach((key) => {
copy[key] = deepCopy(obj[key], cache);
});
return copy;
}
test
// ----- test -----
const t1 = {a: 1, b: {c: [1, 3, 56]}};
const t2 = deepCopy(t1);
t1.b = 'hello world';
console.log('t1', t1);
console.log('t2', t2);
// t1 { a: 1, b: 'hello world' }
// t2 { a: 1, b: { c: [ 1, 3, 56 ] } }
// 循环引用问题
const q1 = {};
const q2 = {
b: q1,
};
q1.a = q2;
// JSON.stringify(q1); // TypeError: Converting circular structure to JSON
const result = deepCopy(q1);
console.log('result', result);
// result { a: { b: [Circular] } }
兼容Date, RegExp, Error实例深拷贝
function deepCopy(obj, cache = []) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const objType = Object.prototype.toString.call(obj).slice(8, -1);
// 考虑 正则对象的copy
if (objType === 'RegExp') {
return new RegExp(obj);
}
// 考虑 Date 实例 copy
if (objType === 'Date') {
return new Date(obj);
}
// 考虑 Error 实例 copy
if (objType === 'Error') {
return new Error(obj);
}
const hit = cache.filter((c) => c.original === obj)[0];
if (hit) {
return hit.copy;
}
const copy = Array.isArray(obj) ? [] : {};
cache.push({original: obj, copy});
Object.keys(obj).forEach((key) => {
copy[key] = deepCopy(obj[key], cache);
});
return copy;
}
const test = {
reg: /[0-9]/g,
name: 'test',
obj: {key: 'value', arr: [1, 2, 3]},
unmounted() {},
date: new Date(),
err: new Error('err copy'),
undefin: undefined
};
test.test = test;
const copy = deepCopy(test);
// console.log('typeof copy.date :', typeof copy.date);
console.log('typeof copy.date :', typeof copy.err);
console.log('copy :', copy);
console.log('copy.reg :', copy.reg);
// typeof copy.date : object
// copy : <ref *1> {
// reg: /[0-9]/g,
// name: 'test',
// obj: { key: 'value', arr: [ 1, 2, 3 ] },
// unmounted: [Function: unmounted],
// date: 2020-12-19T16:59:11.225Z,
// err: Error: Error: err copy
// at deepCopy (/Users/v_lishaohai/Desktop/didi/deepCopy.js:20:16)
// at /Users/v_lishaohai/Desktop/didi/deepCopy.js:34:21
// at Array.forEach (<anonymous>)
// at deepCopy (/Users/v_lishaohai/Desktop/didi/deepCopy.js:33:22)
// at Object.<anonymous> (/Users/v_lishaohai/Desktop/didi/deepCopy.js:52:14)
// at Module._compile (internal/modules/cjs/loader.js:1063:30)
// at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
// at Module.load (internal/modules/cjs/loader.js:928:32)
// at Function.Module._load (internal/modules/cjs/loader.js:769:14)
// at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12),
// undefin: undefined,
// test: [Circular *1]
// }
// copy.reg : /[0-9]/g