浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝
将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象
浅拷贝实现
function clone(target){
let cloneTarget = {};
for(const key in target){
cloneTarget[key] = target[key];
}
return cloneTarget;
}
深拷贝实现
思路:
- 原始类型,无需继续拷贝,直接返回
- 引用类型,创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性执行深拷贝后依次添加到新对象上。
- 兼容数组,开辟新对象时:
let cloneTarget = Array.isArray(target) ? [] : {};
- 对象存在循环引用的情况,即对象的属性间接或直接的引用了自身的情况
解决方案:额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝,这个存储空间,需要可以存储key-value形式的数据,所以选择Map这种数据结构,但是weakmap更好:弱引用让我们不用手动释放占用的内存,垃圾回收机制会将它回收,当你需要拷贝的数据非常庞大时,你就能感受到它的好处。 - 遍历的优化,while的性能最优,所以重写forEach
function forEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
iteratee(array[index], index);
}
return array;
}
暂时考虑set、map、object、array
function deepclone(target, map = new WeakMap()) {
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
// 克隆基本类型
const targetType = typeof target;
if(!(target !== null
&& (targetType === 'object' || targetType === 'function')
)){
return target;
}
// 我们通过原型上的方法拿到type
const type = Object.prototype.toString.call(target);
let cloneTarget;
// 暂时考虑四种可遍历的
const deepTag = ['[object Map]','[object Set]','[object Array]','[object Object]'];
if (deepTag.includes(type)) {
// 拿到对象原型
const Ctor = target.constructor
cloneTarget = new Ctor();
}
// 防止循环引用,判断target被拷贝过了就直接返回,否则去set[key,value]
// weakmap 弱引用,可以被垃圾回收机制回收,避免内存被占用
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);
// 克隆set
if (type === setTag) {
target.forEach(value => {
cloneTarget.add(clone(value,map));
});
return cloneTarget;
}
// 克隆map
if (type === mapTag) {
target.forEach((value, key) => {
cloneTarget.set(key, clone(value,map));
});
return cloneTarget;
}
// 克隆对象和数组
const keys = type === arrayTag ? undefined : Object.keys(target);
// 这里的foreach 是用while改写的,while的遍历性能最快
forEach(keys || target, (value, key) => {
if (keys) {
key = value;
}
cloneTarget[key] = clone(target[key], map);
});
return cloneTarget;
}