下面是一个更为优化的深拷贝函数:
function deepClone(obj, map = new WeakMap()) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
// 如果已经遍历过该对象,则直接返回对应的克隆对象
if (map.has(obj)) {
return map.get(obj);
}
const cloned = Array.isArray(obj) ? [] : {};
// 记录每个需要拷贝的对象和对应的克隆对象的映射关系,用于处理循环引用
map.set(obj, cloned);
Object.keys(obj).forEach(key => {
cloned[key] = deepClone(obj[key], map);
});
return cloned;
}
const obj = { a: 1, b: { c: 2 } };
const clonedObj = deepClone(obj);
console.log(clonedObj); // { a: 1, b: { c: 2 } }
优化点如下:
- 添加了一个可选参数
map
,用于记录每个需要拷贝的对象和对应的克隆对象的映射关系,用于处理循环引用。这里使用了 JavaScript 的弱引用WeakMap
,如果某个拷贝对象已经在该映射表中有对应的克隆对象,则直接返回该克隆对象,避免进入死循环。 - 使用
Object.keys
替换循环遍历对象的方式,更加简洁高效。
下面对代码的每一行进行解释:
function deepClone(obj, map = new WeakMap()) {
:声明一个函数 deepClone,参数为 obj 和可选参数 map,用于实现深拷贝。将 map 的初始值设置为一个空的弱映射表。if (typeof obj !== 'object' || obj === null) { return obj; }
:判断 obj 是否为对象或数组,或者是否为 null,如果不是则直接返回 obj。if (map.has(obj)) { return map.get(obj); }
:如果 map 中已经存在当前要拷贝的对象(即已经遍历过该对象),则直接返回对应的克隆对象,避免进入死循环。const cloned = Array.isArray(obj) ? [] : {};
:声明一个变量 cloned,如果 obj 是数组则将 cloned 赋值为一个空数组,如果 obj 是对象则将 cloned 赋值为一个空对象。map.set(obj, cloned);
:将当前要拷贝的对象和对应的克隆对象的映射关系记录在 map 中。Object.keys(obj).forEach(key => { cloned[key] = deepClone(obj[key], map); });
:使用Object.keys
方法获取 obj 所有可枚举属性的 key,然后遍历每个 key,对 cloned 对象的这个 key 赋值为递归调用 deepClone 函数后返回的值,并传入当前的 map 映射表。return cloned;
:返回最终生成的克隆对象。
调用方式与之前相同,例如:
const obj = { a: 1, b: { c: 2 } };
const clonedObj = deepClone(obj);
console.log(clonedObj); // { a: 1, b: { c: 2 } }