JavaScript中的深拷贝和浅拷贝

本文详细介绍了JavaScript中浅拷贝和深拷贝的概念,通过代码示例展示了浅拷贝的机制(如赋值和Object.assign方法),以及递归实现深拷贝的方法(如JSON.parse和自定义深拷贝函数)。同时指出了一维数组和多维数组在使用扩展符时的浅拷贝/深拷贝区别。
摘要由CSDN通过智能技术生成


拷贝是啥?

在JS中,深拷贝和浅拷贝是针对对象的复制而言的。对象在JS中是引用类型,因此当我们将一个对象赋值给另一个变量时,实际上是将其引用复制了一份。因此,对其中一个变量所做的修改也会影响另一个变量。

浅拷贝
浅拷贝是啥?

浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用(地址),所以改变新对象,旧对象也会改变,因为新旧对象共享一块内存。

代码展示

 let obj = {
		 	    name:"ls",
	 	        sex:"男",
                arr:[1,2,3]
		 };
    let obj1=obj;
    obj1.arr[0]=10;
    console.log(obj.arr[0]);//10


     //Object.assign(目标对象, 源对象, ···)
		 let obj1 = {a:1};
		let obj2 = {b:{d:2}};
		 let obj3 = {c:3};
		 Object.assign(obj3,obj1,obj2);
            console.log(obj3);//{b: {d:2}};
          console.log(obj3);//{a: 1,b: {d:2},c: 3}
		 obj3.b.d = 99;
		 console.log(obj3);//{a: 1,b: {d: 99},c: 3}
		 console.log(obj2);//{b: {d:99}};

从上面第一段代码可以看出当对象中有多层属性时, 正常的赋值就会产生浅拷贝现象,可能有的小伙伴可能对Object.assign()这个方法有点不熟悉,那我就在下面浅介绍一下这个方法

Object.assign(目标对象,源对象1,源对象2…);作用就是将一个或者多个源对象中所有可枚举的自有属性复制到目标对象,并返回修改后的目标对象。

食用说明:

如果目标对象与源对象具有相同的键(属性名),则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的同名属性。

Object.assign() 方法只会拷贝源对象可枚举的的自有属性到目标对象。该方法在源对象上使用 [[Get]],在目标对象上使用 [[Set]],因此它会调用 getter 和 setter。故它对属性进行赋值,而不仅仅是复制或定义新的属性。如果合并源对象包含 getter 的新属性到原型中,则可能不适合使用此方法。

如果要将属性定义(包括它们的可枚举性)复制到原型中,则应改用 Object.getOwnPropertyDescriptor() 和 Object.defineProperty() 方法。

字符串和 Symbol 类型属性都会被复制。

注意:

当对象只有一级属性是不存在浅拷贝;
当对象中有多级属性时,二级属性后就是浅拷贝;
深拷贝
深拷贝是啥?

复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。

代码展示

//使用递归去深拷贝
function deepClone(obj){
		 	 var objs = Array.isArray(obj)?[]:{};
		 	 if(obj&&typeof obj==="object"){
		 		 for(key in obj){
					 if(obj.hasOwnProperty(key)){
		 				 if(obj[key]&&typeof obj[key]==="object"){
	 					 objs[key] = deepClone(obj[key]);
						 }else{
		 					objs[key] = obj[key];
	 				 }
	 			 }
		 		}
		 	 }
			 return objs;
		 }
//使用JSON对象去深拷贝
function deepClone(obj){
			let _obj = JSON.stringify(obj);
			let objClone = JSON.parse(_obj);
			return objClone
		}
		let a=[0,1,[2,3],4],
		b=deepClone(a);

方法分析
递归:

先使用Array.isArray()判断传入的值是数组还是对象
判断obj是不是对象
用for(in)将对象里面第一层的属性全部循环出来
用hasOwnProperty(key)检测传入对象里面的值是不是自有属性
判断obj里面的属性还是不是对象
如果是对象就利用递归将这个值重新传入函数里面直到所有子对象全部进入else
如果不是对象就直接将值加入到另一个对象里面
JSON对象

利用JSON.stringily(obj);将传入的对象先变为字符串格式,用一个变量存起来
利用JSON.parse(_obj)将"“去掉再用一个变量存起来
这样就解决了两个变量指向一个地址的问题了,也就做到了深拷贝
注意:JSON对象这个方法对数组有用,但是对对象没用,原因就是JSON.parse(_obj)虽然可以将”"去除,但是不能去除对象的
在测试的时候我又发现一个问题关于扩展符…的

在一维数组里面使用…就是深拷贝,多维数组就是浅拷贝

测试结果:

//一维数组
	let a=[0,1,4];
		let b=[...a];
        let c=b;
		b[2]=6;
		console.log(a);//0,1,4
		console.log(b);//0,1,6
        console.log(c);//0,1,6
//多维数组
	let a=[0,1,[2,3],4];
		let b=[...a];
        let c=b;
		b[2][0]=6;
		console.log(a);//0,1,[6,3],4
		console.log(b);//0,1,[6,3],4
        console.log(c);//0,1,[6,3],4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明日筑梦师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值