深拷贝与浅拷贝深入理解

1. 什么是深拷贝?什么是浅拷贝?

不管是深拷贝还是浅拷贝,都是针对引用类型的。通俗的理解就是,深拷贝得到的对象不会受被拷贝对象影响,浅拷贝得到的对象与被拷贝对象之间相互影响。

2. 深拷贝的实现

  1. 方式一:手动深拷贝
let school = { name: "milly" }
let my = { age: { count: 18 }, name: "xy" }
let newMy = { ...my, age: { ...my.age } }
let all = { ...school, ...newMy }
console.log(all)

my.age.count = 100
console.log(my)
console.log(all)  // { name: 'xy', age: { count: 18 } }

注意: 展开运算符本身是浅拷贝。Object.assign()等同于...,也是浅拷贝。

  1. 方式二:先把对象转换成字符串, 然后把字符串转换成对象
let school = { name: "milly" };
let my = { age: { count: 18 }, name: "xy" };
let all = JSON.parse(JSON.stringify({ ...school, ...my }));
console.log(all)

my.age.count = 300
console.log(my)  // { age: { count: 300 }, name: 'xy' }
console.log(all)  // { name: 'xy', age: { count: 18 } }

这种深拷贝的方式存在一定的问题:不能拷贝函数、undefined、时间、正则,测试看一下:


  1. 方式三:封装一个深拷贝 — 递归拷贝

首先, 我们可以判断数据类型的方式有:typeofinstanceofObject.prototype.toString.call()constructor

先来看下浅拷贝函数是如何封装的:

function deepClone(obj) {
	if (obj == null) {return obj}
	if (obj instanceof Date) {return new Date(obj)}
	if (obj instanceof RegExp) {return new RegExp(obj)}
	if (typeof obj !== 'object' ) {return obj}

	let cloneObj = new obj.constructor()
	for (let key in obj) {
		if (obj.hasOwnProperty) {
			cloneObj[key] = obj[key]
		}
	}
	return cloneObj
}

如何修改成深拷贝呢? 其实, 深拷贝 = 浅拷贝+递归

function deepClone(obj) {
	if (obj == null) {return obj}
	if (obj instanceof Date) {return new Date(obj)}
	if (obj instanceof RegExp) {return new RegExp(obj)}
	if (typeof obj !== 'object' ) {return obj}

	let cloneObj = new obj.constructor()
	for (let key in obj) {
		if (obj.hasOwnProperty) {
			cloneObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
		}
	}
	return cloneObj
}

// 测试
let obj = {
  school: { name: { first: "mengmeng", last: "Liu" }, age: 18 },
  fn: function () {},
  aa: undefined,
  b: null,
  arr: [1, 2, 3],
}
let obj2 = deepClone(obj)
console.log(obj2)

obj2.school.age = 100
console.log(obj)  

上述深拷贝函数已经能够实现开始的功能了,但是如果是拷贝自身的话,即obj.xxx=obj,就会陷入死循环, 如何解决这个问题呢? 使用 弱引用 Map weakMap Set weakSet。

3. 使用弱引用解决深拷贝中递归死循环的问题

function deepClone(obj, hash = new WeakMap()) {
	if (obj == null) {return obj}
	if (obj instanceof Date) {return new Date(obj)}
	if (obj instanceof RegExp) {return new RegExp(obj)}
	if (typeof obj !== 'object' ) {return obj}

	// 如果拷贝的是一个已经存在的对象,那就直接从WeakMap中返回即可
	if (hash.has(obj)) { return hash.get(obj) }
	let cloneObj = new obj.constructor()
	hash.set(obj, cloneObj)
	for (let key in obj) {
		if (obj.hasOwnProperty) {
			cloneObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key], hash) : obj[key]
		}
	}
	return cloneObj
}

4. 如何解决深拷贝中可能出现的爆栈问题? — 迭代?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值