浅拷贝和深拷贝的区别
浅拷贝
let a = 10;let b=a;a=20console.log(b)//10
1,由于a和b基本类型并且都是在栈中的,它们分别进行保存,所以这里输出的b还是10
2,通过内存可以看出,它们的两个值是独立的,更改其中一个不会影响另外一个。如下图
二,引用类型
let a=[1,2,3]let b=a;//这里通过更改a里面的第一个元素a[0]=10console.log(b)//[10,2,3]
原因: 1,由于是一个引用类型,它存的就不是这个数据,而是一个内存地址; 2,这里声明了一个变量a,但它的值并不是直接存了这个数组,而是内存地址,这个时候它会在堆中开辟一块内存存储这个数据[1,2,3]; 3,a里面存放的就是这个地址,变量a就根据这个地址进行查找; 4,接着在声明了一个变量b,由于a和b引用的是同一个内存地址,它们共用了一个数据,不管是修改a还是b,它们之间都会相互影响;
内存原理图是这样的
如果要实现深拷贝,就需要把a里面的数据重新开辟一块内存空间给b,让b在指向这个内存地址,让它们两个之间互相彼此独立即可
有两种简单的方式进行实现,展开运算符或for循环
let a=[1,2,3]//1,使用展开运算符//let b=[...a];//2,使用for循环let b=[]for(let i=0;i<a.length;i++){b.push(a[i])}a[0]=30console.log(b)//[1,2,3]
实现深拷贝
1,使用JSON
JSON.stringfy() 其实就是将一个 JavaScript 对象或值转换为 JSON 字符串,最后再用 JSON.parse() 的方法将JSON 字符串生成一个新的对象。一般情况下对普通对象需要进行深拷贝,可以使用这种方法进行深拷贝操作,这种是最简单且代码量最少的深拷贝方法
function deepClone(target) {//创建JSON格式的字符串let str = JSON.stringify(target);//将JSON字符串转为JS数据let data = JSON.parse(str);return data;}
缺点:
1,取不到值为 undefined 的 key;
2,如果对象里有函数,函数无法被拷贝下来;
3,对象直接转变为 date 字符串;
function deepclone(target){let str = JSON.stringify(target)let data = JSON.parse(str)return data}let obj={name:"张三",age:18,height:undefined,date:new Date(),arr:[1,2,3],fun:function(){console.log(this.name)}}let deep1=deepclone(obj)console.log(obj)deep1.arr[2]=10console.log(deep1)
2,Object.assign()拷贝
当对象中只有一级属性,没有二级属性的时候,此方法可用。但是有二级属性的时候就会失效。
let obj={name:"张三",age:18,height:undefined,date:new Date(),arr:[1,2,3,{weight:"180"}],fun:function(){console.log(this.name)}}let result = Object.assign({},obj)result.arr[0]=10result.arr[3].weight="190"console.log(obj)console.log(result)
3,使用递归实现简易的深拷贝
//实现数组或方法的深拷贝let obj={name:"张三",age:18,arr:[1,2,3],sun:function(){console.log(this.name+''+this.age)}}function deepClone(Data){if(typeof Data==='object'&&Data!==null){let res = Array.isArray(Data)?[]:{};for(let k in Data){if(Data.hasOwnProperty(k)){res[k]=deepClone(Data[k])}}return res}else{return Data}}let deep1=deepClone(obj)deep1.name="李四"deep1.arr[0]=10deep1.sun=function () {console.log(this.name)}deep1.sun()console.log(deep1)console.log(obj)
最终的返回结果,开辟了两块新的内容,彼此独立互不影响
总结:
1,浅拷贝的是地址指向,原对象修改的时候,新对象的数据也跟着修改,他们指向的是一个对象空间。 2,深拷贝:创建一个一模一样的对象,新对象跟原对象不共享内容(新对象和原对象各自独享内存),修改新对象不会改到原对象。
js中浅拷贝和深拷贝所涉及到的知识点和细节还有很多,这里只做了一个简单的整理。