JavaScript浅拷贝和深拷贝

本文详细解释了浅拷贝和深拷贝的概念及其在JavaScript中的实现方法,包括处理循环引用、特殊类型的拷贝等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浅拷贝:

let obj = {a: 123, b: 456, c: {a:123,b: 456}};
let copy = {}
copy.a = obj.a;
copy.b = obj.b;
copy.c = obj.c;
copy.c.a = 222;
console.log(obj)

在这里插入图片描述
从上面结果可以看出,浅拷贝只拷贝一层。对于obj属性仍然为引用的内容并没有进行拷贝,而是共用了一个,所以对于copy.c.a的修改同时也影响到了obj。

实现一个浅拷贝copy函数:
let obj = {a: 123, b: 456, c: {a:123,b: 456}};
function copy (value) {
	if (typeof value === 'object') {
		let isArray = value instanceof Array
		let rs = isArray? []:{}
		for (let i in value) {
			rs[i] = value[i]
		}
		return rs
	} else {
		return value
	}
}
let newObj = copy(obj);
console.log(newObj)

在这里插入图片描述
当然,如果您知道您拷贝的就是一个数组,那么可以通过arr.slice(0)来实现,或者通过 [].concat()来实现,或者通过es6的…扩展属性来实现let rs = isArray? [...value]: {...value},如果不知道那么就可以通过上述函数方式了。

深拷贝:

实现一个深拷贝:
let obj = {a: 123, b: 456, c: {a:123,b: 456}};
function copy (value) {
	if (typeof value === 'object') {
		let isArray = value instanceof Array
		let rs = isArray? []:{}
		for (let i in value) {
			rs[i] = copy(value[i])
		}
		return rs
	} else {
		return value
	}
}
let newObj = copy(obj);
newObj.c.a = 1111;
console.log(obj)

在这里插入图片描述

通过上面结果可知:深拷贝是完全复制了两份内容,对一份的修改不能影响到另一份的变化。

实现深拷贝的另一种方式:
JSON.parse(JSON.stringify(obj))


然而:

上面那种深拷贝是最简单的情况,针对的是数组和对象的情况,并没有考虑其他数据类型。

复杂情况1:

比如:

let obj = {a: 123, b: 456, c: {a:123,b: 456}};
obj.d = obj;
function copy (value) {
	if (typeof value === 'object') {
		let isArray = value instanceof Array
		let rs = isArray? []:{}
		for (let i in value) {
			rs[i] = copy(value[i])
		}
		return rs
	} else {
		return value
	}
}
let newObj = copy(obj);
newObj.c.a = 1111;
console.log(obj)

运行后会报如下错误:
在这里插入图片描述
错误原因分析:for循环陷入了死循环。
解决办法:

let obj = {a: 123, b: 456, c: {a:123,b: 456}};
obj.d = obj;
function copy (value, map = new Map()) {
	if (typeof value === 'object') {
		if(map.get(value)) {
			return map.get(value);
		}
		let isArray = value instanceof Array
		let rs = isArray? []:{}
		map.set(value, rs)
		for (let i in value) {
			rs[i] = copy(value[i], map)
		}
		return rs
	} else {
		return value
	}
}
let newObj = copy(obj);

console.log(newObj.d)

在这里插入图片描述

复杂情况2:

如何数据类型有symbol,而for循环是对其不支持的。
通过Reflect.ownKeys()解决

let obj = {a: 123, b: 456, c: {a:123,b: 456}};
obj.d = obj;
obj[Symbol('e')]='dadfadf'
function copy (value, map = new Map()) {
	if (typeof value === 'object') {
		if(map.get(value)) {
			return map.get(value);
		}
		let isArray = value instanceof Array
		let rs = isArray? []:{}
		map.set(value, rs)
		// for (let i in value) {
		// 	rs[i] = copy(value[i], map)
		// }
		Reflect.ownKeys(isArray? [...value]:{...value}).forEach(key=>{
			rs[key] = copy(value[key], map)
		})
		return rs
	} else {
		return value
	}
}
let newObj = copy(obj);

console.log(newObj.d)

在这里插入图片描述

复杂情况3:

如果数据类型有Date这些,那又该怎么办?
通过结构化克隆法

let obj = {a: 123, b: 456, c: {a:123,b: 456}, f: new Date};
obj.d = obj;
obj[Symbol('e')]='dadfadf'
function copy (value, map = new Map()) {
	if (typeof value === 'object') {
		if(map.get(value)) {
			return map.get(value);
		}
		let isArray = value instanceof Array
		let rs = isArray? []:{}
		map.set(value, rs)
		switch(value.constructor){
			case Date:
				rs = new value.constructor(value)
				break
			default:
				Reflect.ownKeys(isArray? [...value]:{...value}).forEach(key=>{
					rs[key] = copy(value[key], map)
				})
		}
		// for (let i in value) {
		// 	rs[i] = copy(value[i], map)
		// }
		
		return rs
	} else {
		return value
	}
}
let newObj = copy(obj);

console.log(newObj.d)

在这里插入图片描述

除此之外,还有很多情况需要考虑。。所有JavaScript里深拷贝并不是一个简单的东西,可以参考一下Lodash这个库里如何实现的深拷贝。

整理自:https://www.bilibili.com/video/av49559690?from=search&seid=10412422805049926042

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

. . . . .

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

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

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

打赏作者

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

抵扣说明:

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

余额充值