1. js对象/数组的深度拷贝/复制和浅度拷贝/复制 方法 | 给对象数组添加新字段/修改属性| 前端修改后端传来的值,添加新字段

js对象的深度拷贝/复制和浅度拷贝/复制 方法

概念:

深度拷贝与浅度拷贝的区别主要是在于有没有为拷贝出的新对象在堆中重新分配一块内存区域。

浅度拷贝即直接赋值, 拷贝的只是原始对象的引用地址,在堆中仍然共用一块内存。所以当复制品变化了,原对象也会改变。

arr1=arr2,则arr2被复制了一个引用地址,它俩共用一个内存。

深度拷贝为新对象在堆中重新分配一块内存,所以对新对象的操作不会影响原始对象。

什么情况下要进行深度拷贝?

我们在复制一个对象的时候,对它进行操作,为了不让新对象影响到原始对象,要对它进行深度拷贝。

数组和对象等引用类型的数据都可以进行深度拷贝。

1. 以对象数组为例-比较浅度拷贝和深度拷贝的区别

复制一个arr1数组,为arr2. 并为arr2添加一个新的属性count.

浅度拷贝

// 浅度复制
var  arr1=[
			{
    
    id:1,name:'xiaoming',age:16},
			{
    
    id:2,name:"xiaobai",age:19}
		]
var arr2=[]
function copyarr1(arr){
    
    
		for (var i = 0; i < arr.length; i++) {
    
    
			var obj1=arr[i] //obj1直接复制对象名
			obj1["count"]=0 //给arr2的obj添加新属性
			console.log(obj1)
			arr2.push(obj1)
				
		}

	}
copyarr1(arr1)
console.log("--arr2---")
console.log(arr2)

console.log("--arr1---")
console.log(arr1)

在这里插入图片描述

浅度复制解析

可以看到,为arr2的对象添加了属性count, 原arr1的对象也被添加上了属性。

当arr2复制arr1时,定义的obj1直接让arr1[ i ]赋的值,此时由于arr的子对象arr1[ i ]为引用类型的数据obj.

引用数据类型:名 存在栈内存中,值 存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值.

所以说,obj1实际上只是复制了一个引用地址,并没有把arr1[i]的值复制一遍,obj1和arr1[i] 是两个指针,共用一个值。

而当我们对obj1进行增删改的时候,由于obj1与arr1[i]指向的是同一个值,它俩共用的值变了,所以arr1 [i]指针指向的对象已经变了。
浅度复制

除此之外,因为共用一个值,浅度复制还产生一些其他的影响。

浅度复制在给对象数组添加新字段时的影响

以购物车需求为例:

for (var i = 0; i < state.cartlist.length; i++) {
    
    
				if(state.cartlist[i]["id"]==obj["id"]){
    
    
					// 1 判断新添加的数据如果在购物车list中,count++
					state.cartlist[i]["count"]++
					break;
				}
				//2.如果新数据不在购物车,push进数组
				if(i==state.cartlist.length-1){
    
    
					//商品obj加入购物车列表
					state.cartlist.push(obj);
					state.cartlist[i]["count"]++
					break;
				}
			}

比如说点击按钮调用这个函数添加购物车,新商品id=arr[i].id的时候,也就是购物车已有这条数据,要实现count++,如果是浅度复制的情况下,第一次, obj1=arr[i] 的时候,他们俩公用一个堆里的值,我们给它起名为a, 给obj1添加了属性count,初始值为1。这条对象被push进数组。

那当第二次点击的时候,在判断新商品id=arr[i].id的时候,第二次这个数据还是调用的堆里面这个值,和上次被push进数组的obj相同,所以count要加1,但是在这之前,它要经过添加属性count值这一步,也就是说count还是从1开始加。点击多少次都是从1开始加,满足不了count每次加一的需求。

2. 对象/数组的深度拷贝实现方法

对象/数组的深度拷贝方式一:新建对象,复制属性

我们给arr2的obj1重新定义一个对象,让它挨个复制里面的值,形成一个新对象,然后push进数组arr2,此时,arr2里对象的指针就不再是和arr1[i]相同的了,它是一个独立的新对象,指针是obj1。

arr1=[
			{
    
    id:1,name:'xiaoming',age:16},
			{
    
    id:2,name:"xiaobai",age:19}
		]
	arr2=[]
	function copyarr1(arr){
    
    
		for (var i = 0; i < arr.length; i++) {
    
    
			var obj1={
    
    }
			obj1["id"]=arr[i]["id"]
			obj1["name"]=arr[i]["name"]
			obj1["age"]=arr[i]["age"]
			obj1["count"]=0
			arr2.push(obj1)
		}
	
	}
copyarr1(arr1)

console.log("--arr2---")
console.log(arr2)

console.log("--arr1---")
console.log(arr1)

给arr2的对象里添加属性,arr1指向的值不会跟着改变了,因为arr2的对象已经独立成一个新对象了。
在这里插入图片描述

对象/数组的深度拷贝方式二:遍历属性

如果对象里的属性比较多,挨个复制显然不可取,遍历对象,在遍历内部赋值即可。

var  arr1=[
			{
    
    id:1,name:'xiaoming',age:16},
			{
    
    id:2,name:"xiaobai",age:19}
		]
	var arr2=[]
	function copyarr1(arr){
    
    
		for (var i = 0; i < arr.length; i++) {
    
    
			var obj1={
    
    }
			for(let key in arr[i]){
    
       //遍历arr[i]对象的属性
			     obj1[key] = arr[i][key]
			 }
			obj1["count"]=0  //给obj1添加新的属性
			arr2.push(obj1)
				
		}

	}
copyarr1(arr1)

console.log("--arr2-遍历的方式-------")
console.log(arr2)

console.log("--arr1---")
console.log(arr1)

在这里插入图片描述

对象/数组的深度拷贝方式三:JSON.parse(JSON.stringify(array))

JSON.parse(JSON.stringify(array))可以实现数据类型不是基本变量的数组深度拷贝, 可以理解为二级深度拷贝。

即数组或对象内不是基本类型,而是内部也含有数组或对象。

原理就是把复杂数组变成字符串再变回来。里面的二级对象就成功复制了。

arr=[{
    
    },{
    
    },{
    
    }]
obj={
    
    
	"name":"小白",
	"address":{
    
    
	...
	...
	}
}

拷贝方法:

arr1=JSON.parse(JSON.stringify(arr))
obj1=JSON.parse(JSON.stringify(obj))

实例

当数组里有对象时。

直接复制数组

var  arr1=[
				{
    
    id:1,name:'xiaoming',age:16},
				{
    
    id:2,name:"xiaobai",age:19}
			]

	var arr2=JSON.parse(JSON.stringify(arr1))
	console.log(arr2)
	console.log("===========1===")
	console.log(arr1)

在这里插入图片描述

添加属性

如果数组里的对象需要添加属性,那么遍历数组,深度复制每个对象,再添加属性。

var  arr1=[
			{
    
    id:1,name:'xiaoming',age:16},
			{
    
    id:2,name:"xiaobai",age:19}
		]
	var arr2=[]
	function func1(arr){
    
    
		for (var i = 0; i < arr.length; i++) {
    
    
			var obj1=JSON.parse(JSON.stringify(arr[i]))  //深度复制
			obj1["count"]=0  //更改arr2的对象属性 添加属性count
			arr2.push(obj1)		
		}

	}
func1(arr1)
console.log("--arr2--JSON方式------")
console.log(arr2)
console.log("--arr1--")
console.log(arr1) 

在这里插入图片描述

3. 内部为基本变量的数组 深度复制

数组内部是简单数据类型的操作。

实际上深度复制只是针对数组里有复杂类型的数组或对象 ,因为[{},{},]的这种形式在浅度复制的时候无法复制二级子对象。

这里数组内简单数据类型的深度复制是为了不共用一个堆里面的值,两个指针指向同一个值。为的是分离出单独的指针和值来。与原数组分离开。两者自己的值变了不影响另一个。

浅度复制

//浅度复制
arr1=[1,2,3]
arr2=arr1

深度复制

1.arr.slice()

arr.slice(start,end),返回array从start到end的一个数组片段 ,若没有参数,则返回和array长度相等的数组。

	  var arr = [1,2,3,4];
	  var copyarr = arr.slice();
	  console.log(copyarr);//[1,2,3,4]

2.arr.concat()

array.concat(array1,array2,…),即将array与array1,array2…拼接起来,若不传参数,相当于拼接一个空数组,即返回与自身相同的数组。

	var arr= [1,2,3];
	var copyarr = arr.concat();

3.arr.copyof()

	  var arr= [1,2,3,4];
	  var copyarr = new int[4];
	  copyarr =arr.copyOf(arr,4);

猜你喜欢

转载自blog.csdn.net/yangyangdt/article/details/122469035