什么是深/浅拷贝?和赋值的区别?实现的方案?
浅拷贝:基本数据类型和引用数据类型表现形式不一样,基本数据类型指针指向栈内存,拷贝的是值,引用数据类型指针指向的虽然也是栈内存,但是拷贝的是内存地址,这个地址指向堆内存中的值。所以引用数据类型共用一片内存空间,会造成其中一个对象改变了地址,另一个对象也随之改变。
深拷贝:深拷贝会从堆内存自己开辟一片新的内存区域。
赋值:基本数据类型和引用数据类型拷贝的都是地址
举例:
赋值:修改赋值后的对象b的非对象属性,也会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,也会影响原对象a的对象属性。
浅拷贝:修改赋值后的对象b的非对象属性,不会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,却会影响原对象a的对象属性,
深拷贝:改赋值后的对象b的非对象属性,不会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,也不会影响原对象a的对象属性。
实现方案:
浅拷贝:
object.assigin() concant slice 展开运算符...
深拷贝:
1.乞丐版 JSON.stringfy
function Obj() {
this.func = function () {
alert(1)
}
this.Obj = {a:1};
this.arr = [1,2,3];
this.und = undefined; // 消失
this.reg = /123/ //{}
this.data = new Date(0); // 字符串
this.nan = NaN // null
this.infinity = Infinity; //null
this.sym = Symbol(1) // 消失
}
let Obj1 = new Obj();
Object.defineProperty(Obj1,'innumberable',{
enumerable:false,
value:'innumberable'
}); //无
console.log('obj1',Obj1);
let str = JSON.stringify(Obj1)
let Obj2 = JSON.parse(str)
console.log('obj2',Obj2);
拷贝的对象如果有 函数 undefind symbol 这几种类型 经过序列化后键值对会消失
拷贝data引用类型会变成字符串
无法拷贝 不可枚举属性/对象原型链
拷贝regexp 引用类型会变成空对象
对象中含有NAN , infinity 以及 -infinity ,json序列化的结果会变成null
无法拷贝循环引用
2.基础版: 手写递归
var obj = {
name: 'xiaoming',
age: 10,
arr: [1, 2, 3],
a: {
b: 'xiaoli'
},
und : undefined,
reg :/123/ ,
data :new Date(0),
nan : NaN ,
infinity : Infinity,
sym :Symbol(1),
func :function () {
alert(1)
}
}
Object.defineProperty(obj,'innumberable',{
enumerable:false,
value:'innumberable'
}); //无
function deepClone (obj) {
let cloneObj = Array.isArray(obj) ? [] : {}
for (const key in obj) {
if (obj && typeof obj[key] === 'object') {
cloneObj[key] = deepClone(obj[key])
} else {
cloneObj[key] = obj[key]
}
}
return cloneObj
}
var obj1 = deepClone(obj)
obj1.a.b= 'xiaoli2'
console.log(obj1,'obj1');
console.log(obj,'obj');
不能拷贝symbol 以及不可枚举属性. ????
这种方法只针对普通引用类型的值做递归处理(日期函数 function 正则 错误对象)
对象的属性里面成环,即循环引用没有解决
3.改进版:解决基础版的问题
symbol 以及不可枚举属性用Reflect.ownKeys
参数为data 以及 regex类型 返回新实例
object的getOwnPropertyDescriptors 所有属性以及对应特性,Object的create方法创建一个新的对象并且继承传入原对象的原型链
weakmap,弱引用类型防止内存泄漏,如果有循环,引用直接返回weakMap存储的值