JavaScript的浅拷贝和深拷贝

对象在内存中的存储

上图是对象在内存中存储的情况,我们可以明显的知道obj和obj2是共享同一片地址空间的,如果对其中的任何一个进行修改,都会影响到指向同一片地址空间的其他变量。但是在很多情况下,我们需要复制出来完全一样的对象的内容,这就涉及到拷贝。

拷贝的分类

  • 浅拷贝
  • 深拷贝

要说两者的区别,还得看被复制对象的复杂程度。

let obj1 = {
    name: 'mzy',
    age: 20
}
let obj2 = {
    name: 'mzy',
    nickName: ['mzt','zyd']
}

如果是第一种情况,即对象中的value,都是基本数据类型,那么深拷贝和浅拷贝的结果是完全一致的。
如果是第二种情况,对于浅拷贝,value是基本数据类型是复制的,但是如果value也是对象(数组也属于对象),那么复制的对象和原对象还是共享同一片地址空间的,而深拷贝则是完全不同的地址空间。(即浅拷贝只是解决了对象第一层包裹的问题,多层包裹的情况没有解决)

当然,对于浅拷贝的难度相对于深拷贝难度不是很大,深拷贝需要考虑多种情况,我也写不出来完美的深拷贝。

浅拷贝

Object.assign(target,…sources)

Object.assign()可以接受多个参数,第一个参数是目标对象,2-N个参数是需要复制的对象

let obj = {
    name: 'mzy',
    age: 20
}
let shallowCopy = Object.assign({},obj);

当然我这里只是简单的提及一下方法,其实还有很多其他情况,有兴趣的同学可以看阮一峰老师的es6或者是MDN有关文档
阮一峰老师的es6入门MDN文档

展开运算符(…)

这个是es6提供的方法,用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let obj = {
    name: 'mzy',
    age: 20
}
let arr = [1,2,3,4];
let shallowCopy1 ={...obj}
let shallowCopy2 = [...arr];

手动实现

当然自己实现一个浅复制

function shallowCopy(target){
	let obj = target instanceof Array ? [] : {};
	for(let i in target){
		obj[i] = target[i];
	}
	return obj;
}

深拷贝

JSON.parse(JSON.stringify(target))

这个是经常使用的一种方法,但是有局限性

  • 会忽略undefined
  • 不能序列化函数
  • 不能解决循环引用的对象
    let obj = {
		name: 'mzy',
		nickName: ['mxt','zyd'],
		age: undefined,
		getName: function(){
			return this.name;
		}
	}
	let deepCopy = JSON.parse(JSON.stringify(obj)); // {name: "mzy" nickName: (2) ["mxt", "zyd"]}
    // 无法解决第三点
    let obj = {
		a: 1
		b: {    
			c: 2,
			d: 3,  
		}, 
	}
	obj.c = obj.b 
	obj.e = obj.a 
	obj.b.c = obj.c 
	obj.b.d = obj.b 
	obj.b.e = obj.b.c 
	let deepCopy = JSON.parse(JSON.stringify(obj)); // 报错:Uncaught SyntaxError: Unexpected identifier

手动实现

当然自己也可以手动实现一个简单的深复制

// 只考虑Array和Object
    function checkType(target){
		return Object.prototype.toString(target).slice(8,-1);
	}
	function deepCopy(target){
		let result = null;
		let targetType = checkType(target);
		if(targetType === "Object"){
			result = {}
		}else if(targetType === "Array"){
			result = []
		}else{
			 return target;
		}
		for(let i in target){
			let value = target[i];
			if(checkType(value) === "Object" || checkType(value) === "Array"){
				result[i] = deepCopy(target)
			}else{
				result[i] = value;
			}
		}
		return result;
	}

其实这只是一个最简单的深拷贝,深拷贝还需要考虑的情况很多,例如:循环应用、Symbol、new Date等多种复杂情况。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值