一、实现原理
1. 对象类型的深拷贝
function deepClone(source, map = new Map()) {
if (source === null || typeof source !== "object") {
return source;
}
if (map.get(source)) {
return map.get(source);
}
let target = Array.isArray(source) ? [] : {};
map.set(source, target);
Object.keys(source).forEach(key => {
if (source.hasOwnProperty(key)) {
target[key] = deepClone(source[key], map);
}
});
return target;
}
2. 基本数据类型的深拷贝
function deepClone(data) {
return JSON.parse(JSON.stringify(data));
}
以上代码中出现了一个新的概念:Map,它的用途是用来记录已经拷贝过的对象,避免重复拷贝。
二、应用场景
1. 场景一:对象中的数据饱含了业务逻辑,需要对其进行深度拷贝。
例如,业务中有一个 order 对象,它包含了订单信息、购物车信息等,这个对象的数据量很大,而且其中的对象结构非常复杂,如果使用浅拷贝,可能会只获取到其中的部分数据,而导致业务出现问题。这时就需要使用深拷贝。
2. 场景二:函数中参数传递的时候,需要对复杂对象进行拷贝,避免原始对象被修改,影响其他业务逻辑。
假设在一个项目中,有一个函数需要接收一个对象作为参数,而这个对象可能被多个其他函数调用,如果这个对象是一个被挂载在全局变量上的单例对象,那么很可能在调用函数的过程中被其他函数改变,从而导致程序失去控制。这时就可以在函数中使用深拷贝,每次将数据进行拷贝,避免了原始对象被修改的情况。
三、深拷贝的缺点和注意事项
1. 深拷贝会消耗大量的内存空间和运算时间,当数据量过大的时候,可能会导致性能问题。
2. 如果拷贝对象包含递归引用,例如 A 对象中的某个属性引用了 A 对象本身,那么拷贝函数会陷入无限递归的死循环,导致浏览器或者 Node.js 服务器崩溃。
3. 对于一些不可拷贝的数据类型,例如函数、正则表达式、Promise 等,需要特殊处理。
四、总结
ES6中的深拷贝是基于递归和 Map 数据结构实现的,可以在复杂数据类型的业务场景中避免出现因为浅拷贝而导致的数据不完整或失真的情况。在实际应用中,需要根据业务情况来选择使用深拷贝或浅拷贝,并且需要避免滥用深拷贝,以免导致性能问题。