手写深拷贝和浅拷贝

前言

  本文主要说明如何实现深拷贝和浅拷贝。

一、代码

1、浅拷贝

  浅拷贝是创建一个新对象,这个新对象有着原始对象属性值的一份拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。

// 浅拷贝
function shallowClone(obj) {
	if(obj === undefined) return undefined
	if(obj === null) return null
	// 数据是基本型数据,直接返回
	if(typeof obj !== 'object') return obj
	// 对象为空,直接返回
	if(!Object.keys(obj).length) return obj
	// 据obj的类型判断是新建数组还是对象
	let newClone = Array.isArray(obj) ? [] : {}
	for(let key in obj) {
		//判断当前对象/数组是否有自身的属性 不包括继承
		// 核心
		if(obj.hasOwnProperty(key)) {
			// 赋值给新对象/数组
			newClone[key] = obj[key]
		}
	}
	return newClone
}

2、深拷贝

  深拷贝是创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

// 深拷贝:采用循环递归方式
function deepClone(obj, wm = new WeakMap()) {
	// 对数据预处理
	if(obj === undefined) return undefined
	if(obj === null) return null
	if(obj instanceof Date) return new Date(obj)
	if(obj instanceof RegExp) return new RegExp(obj)
	if(obj instanceof Error) return new Error(obj.message)
	
	// 中断条件
	// 若数据是基本类型,则直接返回不拷贝
	// 对象为空,则直接返回不拷贝
	if(typeof obj !== 'object') return obj
	if(!Object.keys(obj).length) return obj
	// 若WeakMap已存在指定键的元素,则直接存储返回元素,不必重新建立若引用,节约空间
	if(wm.has(obj)) return wm.get(obj)
	
	// obj若为实例对象,使用其构造函数创建新实例对象,新对象包含于obj相同的属性
	// obj若为普通对象,new obj.constructor()等价于new Object()
	// 为什么?执行 obj = { age: 19 };console.log(obj.constructor == Object) 一下就知道了
	let newClone = new obj.constructor()
	wm.set(obj, newClone)
	for(let key in obj) {
		if(obj.hasOwnProperty(key)) {
			// 核心
			newClone[key] = deepClone(obj[key], wm)
		}
	}
	return newClone
}

  为什么使用 WeakMap ?

  主要为了解决 循环引用 的问题。循环引用(circular references)是指在对象之间存在相互引用的情况,形成一个闭环,导致对象无法被完全释放和垃圾回收。循环引用发生在当一个对象的属性或成员引用另一个对象,并且这个被引用的对象又直接或间接地引用回原始对象,从而形成一个循环。
  当存在循环引用时,JavaScript的垃圾回收机制可能无法正确地处理这些对象,因为它们之间的引用形成了一个无法访问的闭环,无法确定哪些对象是不再被使用的。这可能导致内存泄漏,即占用的内存无法被回收,最终导致内存资源的浪费和性能问题。

二、测试代码

// 1、浅拷贝
console.log('浅拷贝')
const str1 = '123'
const str2 = shallowClone(str1)
console.log('str2 : ', str2)
console.log('str1 === str2 : ', str1 === str2)
console.log('-------------------------')
const obj1 = {
    name: 'init',
    arr: [1, [2, 3], 4],
}
const obj2 = shallowClone(obj1)
console.log('obj1 === obj2 : ', obj1 === obj2, '\nobj2 = ', obj2)
console.log('-------------------------')
obj2.name = 'new'
obj2.arr[1] = [4, 5, 6]
console.log('obj1 : ', obj1)
// 属性的引用类型,新旧对象还是共享同一块内存
console.log('obj2 : ', obj2)
console.log('----------------------------------------------------------')

// 2、深拷贝
console.log('深拷贝')
let deep = {
   name: 'shuaige',
   age: 12,
   boo: true,
   n: null,
   un: undefined,
   sy: Symbol('xx'),
   big: 10n,
   child: {
       ele: 'boby',
       x: 100
   },
   arr: [1, 2, 3],
   reg: /^\d+$/,
   fn: function () {
       console.log(this.name);
   },
   time: new Date(),
}
const newDeep = deepClone(deep)
// 循环使用
newDeep.loop = newDeep
console.log(newDeep)

三、结果

在这里插入图片描述
在这里插入图片描述

相关推荐

  1. 拷贝拷贝

    2024-04-25 11:00:02       38 阅读
  2. 拷贝拷贝

    2024-04-25 11:00:02       33 阅读
  3. 讲清楚拷贝拷贝

    2024-04-25 11:00:02       65 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-25 11:00:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-25 11:00:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-25 11:00:02       82 阅读
  4. Python语言-面向对象

    2024-04-25 11:00:02       91 阅读

热门阅读

  1. 数据安全风险评估流程

    2024-04-25 11:00:02       33 阅读
  2. 使用Spring Boot整合定时任务(Schedule)

    2024-04-25 11:00:02       38 阅读
  3. C#基础内容之枚举

    2024-04-25 11:00:02       30 阅读
  4. 汇编实现缓冲区溢出1

    2024-04-25 11:00:02       30 阅读
  5. C++ //练习 13.34 编写本节所描述的Message。

    2024-04-25 11:00:02       32 阅读
  6. 学习 Rust 的第十天:枚举和模式匹配

    2024-04-25 11:00:02       34 阅读
  7. 桌面运维类面试非技术问题

    2024-04-25 11:00:02       29 阅读
  8. yolov5 C3改进|深度可分离卷积轻量化主干

    2024-04-25 11:00:02       35 阅读
  9. mysql的基本用法

    2024-04-25 11:00:02       33 阅读
  10. Netty websocket配置wss

    2024-04-25 11:00:02       33 阅读
  11. 【QEMU系统分析之启动篇(十一)】

    2024-04-25 11:00:02       36 阅读