js 深拷贝和浅拷贝


前言

本文介绍js中深拷贝和浅拷贝的几种方法,以及深拷贝和浅拷贝的区别


深拷贝和浅拷贝的区别

  • 深拷贝(复杂):复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制;
  • 浅拷贝:复制一份引用,所有引用对象都指向一份数据,并且都可以修改这份数据

深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象。它们最根本的区别在于是否真正获取了一个对象的复制实体,而不是引用。简单来说,假设B复制了A,当修改B时,看A是否会发生变化,如果A变了,说明是浅拷贝;如果A没变,那就是深拷贝

浅拷贝

1.直接赋值

代码如下(示例1):

var obj = {
	name:123,
	list:[1,2,3,4,5],
	fn(){
		alert(this.name)
	},
	info:{
		title:'标题',
		subtitle:'副标题'
	}
};
var obj2 = obj;
obj2.name = 456;
obj2.list.push(6,7,8);
console.log(obj2.name,obj.name) //456,456
console.log(obj2.list,obj.list) //[1,2,3,4,5,6,7,8],[1,2,3,4,5,6,7,8]

示例1中将obj直接赋值给obj2,当修改obj2里任意属性时,obj也会被修改

2.for…in

代码如下(示例2):

var obj = {
	name:123,
	list:[1,2,3,4,5],
	fn(){
		alert(this.name)
	},
	info:{
		title:'标题',
		subtitle:'副标题'
	}
};
var obj2 = {};
for(let x in obj){
	obj2[x]=obj[x]
};
obj2.name = 456;
obj2.list.push(6,7,8);
obj2.info.title = '我是obj2的标题';
console.log(obj2.name,obj.name) //456,123
console.log(obj2.list,obj.list) //[1,2,3,4,5,6,7,8],[1,2,3,4,5,6,7,8]
console.log(obj2.info.title,obj.info.title)//我是obj2的标题,我是obj2的标题

示例2通过for…in循环,将obj里的每一项数据都赋值到obj2里。当修改obj2.name时,obj.name不会发生变化,但是修改obj2.list和obj2.info.title时,obj.info.title和obj.list也会发生变化

3.Object.assign

代码如下(示例3):

var obj = {
	name:123,
	list:[1,2,3,4,5],
	fn(){
		alert(this.name)
	},
	info:{
		title:'标题',
		subtitle:'副标题'
	}
};
var obj2 = Object.assign({},obj);
obj2.name = 456;
obj2.list.push(6,7,8);
obj2.info.title = '我是obj2的标题';
console.log(obj2.name,obj.name) //456,123
console.log(obj2.list,obj.list) //[1,2,3,4,5,6,7,8],[1,2,3,4,5,6,7,8]
console.log(obj2.info.title,obj.info.title)//我是obj2的标题,我是obj2的标题

示例3,结果同for…in循环

总结

当拷贝的属性不为array和object时,使用for…in和Object.assign可以实现深拷贝,否则,array和object为浅拷贝


深拷贝

1.JSON.parse(JSON.stringify())

代码如下(示例4):

var obj = {
	name:123,
	list:[1,2,3,4,5],
	tel:/^1[345789]\d{9}$/,
	time:new Date(),
	fn(){
		alert(this.name)
	},
	info:{
		title:'标题',
		subtitle:'副标题'
	}
};
var obj2 = JSON.parse(JSON.stringify(obj))
obj2.name = 456;
obj2.list.push(6,7,8);
obj2.info.title = '我是obj2的标题';
console.log(obj2.name,obj.name) //456,123
console.log(obj2.list,obj.list) //[1,2,3,4,5,6,7,8],[1,2,3,4,5]
console.log(obj2.info.title,obj.info.title)//我是obj2的标题,标题
console.log(obj2.tel,obj.tel)//{}, /^1[345789]\d{9}$/
console.log(obj2.time,obj.time)//2021-03-22T07:58:26.788Z,Mon Mar 22 2021 15:58:26 GMT+0800 (中国标准时间)
obj2.fn() //Uncaught TypeError: obj2.fn is not a function

示例4,看似实现了对obj对象的深拷贝,但这样导致了fn事件的丢失、正则失效、时间格式发生变化

2.递归

递归所有层级属性
代码如下(示例5):

function deepCopy(obj) {
  if (typeof obj === 'object') {
    var result = obj.constructor === Array ? [] : {};
    for (var i in obj) {
      result[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i];
    }
  } else {
    var result = obj;
  }
  return result;
}
var obj = {
	name:123,
	list:[1,2,3,4,5],
	fn(){
		alert(this.name)
	},
	info:{
		title:'标题',
		subtitle:'副标题'
	}
};
var obj2 = deepCopy(obj)
obj2.name = 456;
obj2.list.push(6,7,8);
obj2.info.title = '我是obj2的标题';
console.log(obj2.name,obj.name) //456,123
console.log(obj2.list,obj.list) //[1,2,3,4,5,6,7,8],[1,2,3,4,5]
console.log(obj2.info.title,obj.info.title) //我是obj2的标题 标题
obj2.fn(); //alert(456)

案例5,不仅实现了对array和object对象的深拷贝,还实现了对function的拷贝。

总结

如果对象中没有函数、正则、date,可以使用JSON.parse(JSON.stringify())来实现深拷贝,否则,需要使用递归来循环所有层级的属性


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值