深拷贝实现

概念

首先我们要知道深拷贝不仅是将源对象的各个属性逐个复制过去,还深层递归各属性所包含的对象。深拷贝是开辟新的栈,目标对象和源对象的地址是不同的,两者互不影响。

-和原数据是否指向同一对象第一层数据为基本数据类型原数据包含子对象
赋值改变会使原数据一同改变改变会使原数据一同改变
浅拷贝改变不会使原数据一同改变改变会使原数据一同改变
深拷贝改变不会使原数据一同改变改变不会使原数据一同改变

实现

场景
在实现深拷贝时我们还需要考虑的几个因素:

  • 传入的对象是使用对象字面量的形式创建还是使用构造函数创建
  • 构造函数创建的对象,要如何处理原型链上的属性
  • 循环引用导致的一些问题,如栈溢出

我们先来看看以下三种常见的深拷贝的方法:

  1. JSON.parse(JSON.stringify())
  2. 使用递归实现
  3. 使用 Object.create() 方法实现
1、JSON.parse(JSON.stringify())

这种方法其实在实际中是很常见的。
首先,JSON 中的 stringify 会把一个 JavaScript 对象序列化为一个 JSON 字符串,而 parse 又会把 JSON 字符串反序列化为一个 JavaScript 对象,通过这两种方法的结合,我们就可以实现一个简单的深拷贝。

function jsonClone(obj) {
	return JSON.parse(JSON.stringfy(obj));
}

虽然说这个方法简单粗暴,但是不得不说,想要走捷径,总会踩到坑。这个方法有很大的弊端:

  1. JSON.stringify() 序列化 JavaScript 对象时,所有的函数和原型成员 constructor 都会被有意忽略掉。而且如果某个属性的值是 undefined 也会被过滤掉(注意 null 不会被过滤)。所以这个方法传递的对象中的属性值只能是 Number、Array、String、Boolean、扁平对象 ,即能被 JSON 直接表示的数据结构。
jsonClone({a: 1, b: null, c: function(){}})
// Object { a: 1, b: null }
  1. 第二个问题就是无法解决 循环引用 的问题。(这个场景确实少见)
const a = { val: 2 };
a.target = a;

jsonClone(a)
// Uncaught TypeError: cyclic object value
// 拷贝 a 会出现系统栈溢出,因为出现了 无限递归 的情况。
  1. 也无法拷贝一些 特殊对象,如:RegExp、Date、Set、Map 等。
  2. 补充第一条,除了忽略 undefined 之外,还会忽略 symbol
2、递归实现

说起来其实就是手写一个方法,通过递归调用来实现深拷贝。

function deepClone(obj) {
	// 数据类型为引用数据类型
	if (typeof obj === 'object') {
		// 初始化返回结果
		let result = Array.isArray(obj)? []: {};
		for (let key in obj) {
			// 避免相互引用出现死循环导致爆栈
			if (obj === obj[key]) {
				continue
			}
			if (obj.hasOwnProperty(key)) {
				// 递归调用
				result[key] = deepClone(obj[key])
			}
		}
		return result;
	} else {
		// 基本数据类型,直接返回
		return obj
	}
}

当然,这个方法其实也是有缺陷的,比如和上一个一样,没法拷贝一些特殊对象。

let mapData1 = new Map();
mapData1.set('a', 'fsd'); // Map { a → "fsd" }
deepClone(mapData1); // Object {  }

不过我们在里面对于会引起栈溢出的这种情况,做出了处理,可以避免爆栈发生。

3、Object.create()

我们在上面一个方法的基础上改动一下,不使用递归,而使用更优雅的 Object.create() 来实现。

function deepClone(obj) {
	// 数据类型为引用数据类型
  if (typeof obj === 'object') {
    // 初始化返回结果
    let result = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        // 调用 Object.create
        result[key] = typeof obj[key] === 'object' ? Object.create(obj[key]) : obj[key]
      }
    }
    return result;
  } else {
    // 基本数据类型
    return obj
  }
}

————————————————

原文链接:https://blog.csdn.net/qq_42345237/article/details/120319367

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值