1.浅拷贝与深拷贝
简单来讲,浅拷贝是指向和拷贝对象相同的内存地址,因为是共用一个地址,所以当拷贝对象发生变化时,我们新的对象也会发生变化。
深拷贝的话,我们是开辟了一块新的内存地址来存放新的对象,这样两个对象是指向不同内存地址,所以对于被拷贝对象进行修改时,不会影响到拷贝的对象。
如浅拷贝:
let a=[0,1,2,3,4],
b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
再例如**简单数组的深拷贝(没有嵌套层级)**的深拷贝
当然这里只是进行简单的复制,不算真正意义上的深拷贝。
基本数据类型的话,浅拷贝深拷贝的概念不严谨,因为如果是基本数据类型,都是存储在栈中,一旦声明就会有新的内存空间,这样看都是深拷贝,所以说基本数据类型是没有深浅拷贝的说法,深浅拷贝都是针对复杂数据类型来说的。
基本数据类型:number,string,boolean,null,undefined,symbol,BigInt七个
复杂数据类型:对象,数组,函数等
1.基本数据类型的存值–键值存在栈内存中,let a= 1;
当你b=a复制时,栈内存会新开辟一个内存,例如这样:
基本数据类型修改任何一个都对其他不影响
2.引用数据类型–名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,就是深拷贝!
简单数组(对象)的深拷贝(无层级嵌套)
1.Object.assign()–针对对象
Object.assign是用于对象的合并,它可以将一个或多个可枚举的对象合并到一个新的对象(注意:这里如果对象有继承的属性,则不会合并过去)
对其一个属性进行改变
这里我们的obj对象只是第一层键值对,所以在这里就是进行的深拷贝,我们改变obj的name但是obj2的name没有发生变化。但是对于深层次的对象来说就不一样了。
两个都变,obj2里已经发生变化了,我们可以这样理解Object.assign()对于第一层数据进行了深拷贝,但是对于深层次的数据就进行了浅拷贝。
在这里需要注意一点,Object.assign()是合并对象的,如果是字符串,则会以有序列的对象形式拷贝到对象中
那为什么Object.assign只能实现一层的深拷贝呢;看下它的源码就理解了,它方法中写的也只是简单的赋值复制
2.扩展运算符–对象数组都可
扩展运算符将一个数组和对象转为用逗号分隔的参数序列
3.数组的concat方法–针对数组
4.数组的slice方法–针对数组
对于数组项是引用类型的数据(有层级嵌套),就无法实现深拷贝了。
真正的深拷贝(层级嵌套)
1.JSON方法
利用JSON.stringify()转化为JSON字符串,然后再转回;字符串是基本数据类型,所以这样就可以各占内存,各不影响;
这就是为什么JSON可以实现深拷贝的原因
2.函数库lodash的_.cloneDeep方法(没用过)
3.递归实现深拷贝
参考链接:https://blog.csdn.net/Deku_Ln/article/details/110628565