• 手写深拷贝和浅拷贝


    前言

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

    一、代码

    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

      为什么使用 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    三、结果

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

  • 相关阅读:
    文档、视频、图片上传(点击、拖拽、批量导入)要‍‍‍‍怎么实现?!
    使用Java解压和压缩文件
    [源码解析] TensorFlow 分布式之 ParameterServerStrategy V1
    基础课6——开放领域对话系统架构
    IDEA 启动 java web 老项目
    HPC入门教程(OpenPBS )
    vue---------商城pc端 购物车模块
    解决 safetensors_rust.SafetensorError: Error while deserializing header: HeaderTooLarge
    三步实现支付宝支付【go语言 支付宝沙箱】
    计算机硬件和软件
  • 原文地址:https://blog.csdn.net/qq_45438471/article/details/138156425