目录
1. 浅拷贝深拷贝
狭义上的深浅拷贝只是针对引用数据类型而言的,基本数据类型只有赋值操作
-
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;修改拷贝后的数据对原数据有影响
如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址 -
深拷贝:开辟一块新的内存地址用于存放复制的对象,新对象和原对象不共享内存,修改新对象不会影响原对象
2. 浅拷贝实现方法
Object.assign
Object.assign({},obj):日常开发中常用的一种涉及‘深浅拷贝’的方式;
当obj是单层对象时,此时的Object.assign()能实现“深拷贝”;
而当obj为多层对象时,那么Object.assign({},obj)只能视为‘浅拷贝’
扩展运算符、slice、concat
和assign一样只拷贝一层
3. 深拷贝实现方法
JSON.stringify和JSON.parse
JSON.parse(JSON.stringify(xxx)):JSON 序列化,是日常工作中使用最多的,能解决大部分问题的方法。
这种组合能实现普通对象的深拷贝,而实现function,Symbol(),undefined、Date、RegExp这几种时,会造成数据丢失,原因是 JSON 不支持这些数据类型。
const obj={
age:18,
name:'zy',
address:'changsha',
};
var result = JSON.parse(JSON.stringify(obj))
result.age=23;
console.log(obj) //{age: 18, name: 'zy', address: 'changsha'}
console.log(result) //{age: 23, name: 'zy', address: 'changsha'}
第三方库 lodash
lodash.cloneDeep(obj)
4. 深拷贝手写
主要实现思想:通过递归思维,遍历所需进行深拷贝的对象,直到里边的都是基本数据类型,然后再进行赋值,就是深度拷贝。
利用WeakMap / Map来解决循环引用的问题:解决循环引用的问题其实很简单,只需要在每次对复杂数据类型进行深拷贝前保存其值,如果下次又出现了该值,就不再进行拷贝,直接截止。
function deepClone(obj){
//判断是不是对象
if(typeof obj!=='object' || obj==null) return obj;
if(obj instanceof Date) return new Date(obj); //日期值
if(obj instanceof RegExp) return new RegExp(obj); //正则
//确定是数组还是对象
let newObj = (obj instanceof Array) ? [] : {};
//循环+递归
for (let i in obj) {
if(obj.hasOwnProperty(i)){
newObj[i] = deepClone(obj[i]);
}
}
return newObj;
}
const newObj = deepClone(obj)
newObj.address.school='ahu'
console.log(newObj)
console.log(obj)
//解决循环引用
function deepClone(obj, map=new WeakMap()){
if(typeof obj!=='object' || obj==null) return obj; //判断是不是对象
if(obj instanceof Date) return new Date(obj); //日期值
if(obj instanceof RegExp) return new RegExp(obj); //正则
let newObj = (obj instanceof Array) ? [] : {};
//let newObj = new obj.constructor() //创建一个和obj类型一样的对象
if(map.get(obj)) return map.get(obj); //防止循环引用
map.set(obj,newObj);//放入缓存中
//循环+递归
for (let i in obj) {
if(obj.hasOwnProperty(i)){
newObj[i] = deepClone(obj[i],map);
}
}
return newObj;
}
const obj = {
age:18,
address:{
school:'csu'
},
}
obj.info = obj
let newObj = deepClone(obj)
console.log(newObj)
console.log(newObj.address === obj.address) //false