1. 准备一个包含多种数据类型的对象
let obj1 = {
arr: [1, 2, 3],
arrayOfObjs: [{ c: 5 }, { d: 6 }],
object: { val: 4 },
// 增加一个属性
fn: function () {
return 5;
},
map: new Map(),
set: new Set(),
date: new Date(),
reg: /aa/,
nul: null,
undef: undefined
};
// 环形对象
var obj2 = {
to: obj1
};
obj1.to = obj2;
2. 手写自己的深拷贝函数
- 定义自己的深拷贝函数
function deepClone(obj) {
}
思路点:
- 基本数据类型 undefined null function统一进行处理
if (typeof obj !== 'object' || !obj) {
return obj;
}
- 非对象和非数组的数据都要单独处理,比如Map、Set、RegExp等
let tmp;
// 处理非对象和数组
if (obj instanceof Map) {
tmp = new Map();
cache.set(obj, tmp);
obj.forEach((val, key) => {
tmp.set(deepClone(key), deepClone(val))
})
} else if (obj instanceof Set) {
tmp = new Set();
cache.set(obj, tmp);
obj.forEach(val => {
tmp.add(deepClone(val))
})
} else if (obj instanceof RegExp || obj instanceof Date) {
tmp = new obj.constructor(obj);
cache.set(obj, tmp);
} else {
tmp = new obj.constructor();
cache.set(obj, tmp);
for (let key in obj) {
tmp[key] = deepClone(obj[key]);
}
}
- 单独处理环形对象,避免带来其的递归栈内存溢出
- 新增Map数据类型来存放要处理的对象,为了避免强引用使用WeakMap定义
- 并增加是否包含的判断,对于已经处理过的数据,就不再进行递归(针对环形数据进行的处理)
let cache = new WeakMap(); // 避免强引用
// 每种数据处理逻辑里新增代码
cache.set(obj,tmp);
//并在每次递归进来,处理完基本数据类型后面新增判断是否处理过的代码
if (cache.has(obj)) {
return cache.get(obj);
}
3. 完整代码
// 处理环形对象带来的递归栈内存溢出
let cache = new WeakMap(); // 避免强引用
let cloned = deepClone(obj1);
function deepClone(obj) {
// 处理了基本数据类型 undefined null function
if (typeof obj !== 'object' || !obj) {
return obj;
}
if (cache.has(obj)) {
return cache.get(obj);
}
let tmp;
// 处理非对象和数组
if (obj instanceof Map) {
tmp = new Map();
cache.set(obj, tmp);
obj.forEach((val, key) => {
tmp.set(deepClone(key), deepClone(val))
})
} else if (obj instanceof Set) {
tmp = new Set();
cache.set(obj, tmp);
obj.forEach(val => {
tmp.add(deepClone(val))
})
} else if (obj instanceof RegExp || obj instanceof Date) {
tmp = new obj.constructor(obj);
cache.set(obj, tmp);
} else {
tmp = new obj.constructor();
cache.set(obj, tmp);
for (let key in obj) {
tmp[key] = deepClone(obj[key]);
}
}
return tmp;
}