深拷贝的四种递归实现

实现深拷贝原理的递归方法:遍历对象,数组甚至内部都是基本的数据类型

这是第一种,还算是比较简单。注释都比较详细了,这里就不多加赘述

//实现深拷贝原理的递归方法:遍历对象,数组甚至内部都是基本的数据类型,然后复制它们,即深度复制
var obj = {
    // 原数据,包含字符串,对象,函数,数组等不同类型
    name:"test",
    main:{
        a:1,
        b:2
    },
    fn:function(){

    },
    freinds:[1,2,3]
}
function copy(obj){
    let newobj = null;//声明一个变量用来储存拷贝以后的内容
    // 判断数据类型是否是复杂类型,如果是则调用自己,再次循环,如果不是,直接赋值即可
    // 由于null不可以循环但循环又是object,所以需要对null进行判断
    if(typeof(obj)==='object'&&obj !==null){
        // 声明一个变量用来存储拷贝出来的值,根据参数的不同类型声明不同的值来进行存储
        newobj = obj instanceof Array?[]:{}
        // 循环obj中的每一个项,如果里面还有复杂的数据类型,则进行递归
        for(var i in obj){
            newobj[i] = copy(obj[i])
        }
    }
    else{
        newobj = obj
    }
    console.log('77',newobj)
    return newobj;//函数必须要有返回值,否则结构为undefined
}
var obj2 = copy(obj)
obj2.name = 'test1'
obj2.freinds[2] = 100
obj2.main.b = 1000

console.log(obj)
console.log(obj2)

递归处理,引用类型,保持数据类型

第二种递归深拷贝,Object.create(null),初始化一个新对象

//2.递归处理,引用类型,保持数据类型

// 2.递归处理 引用类型  保持数组类型
function deepCopy(target){
    if(typeof target ==='object'){
        const newTarget = Array.isArray(target)?[]:Object.create(null)
        for(const key in target){
            newTarget[key] = deepCopy(target[key])
        }
        return  newTarget
    }
    else{
        return target
    }
}

这里着重说一下,其实第一个递归类型就是不管三七二十一,不管是基本类型还是引用类型统统一股脑都递归,这样其实对于优化是不利的,基本数据类型其实可以不需要递归的,第二种的代码就做了修改,只针对引用类型,

const newTarget = Array.isArray(target)?[]:Object.create(null)

用的很妙,怎么说呢。如果这个object类型是数组类型,那么则让他继续保持着,如果不是的话则创建一个新对象,使newTarget终有所依,注意在递归里面一定要返回。然后不断的赋值给newTarget

哈希表Map支持循环引用

function deepCopy(target, h = new Map) {
        if (typeof target === 'object') {
                if (h.has(target)) return h.get(target)
                const newTarget = Array.isArray(target) ? [] : Object.create(null)
                for (const key in target) {
                        newTarget[key] = deepCopy(target[key], h)
                }
                h.set(target, newTarget)
                return newTarget
        } else {
                return target
        }
}

//这段代码实现了一个深拷贝函数,用于将一个对象或数组进行深拷贝,生成一个全新的对象或数组,以避免修改原始对象或数组时产生副作用。

具体来说,这个函数接受两个参数:要拷贝的目标对象或数组 target,以及一个记录已经拷贝过的对象的 Map 对象 h,默认值为一个新的 Map 对象。

首先,函数会判断目标对象的类型是否为对象(包括数组和普通对象),如果不是对象类型,则直接返回目标对象本身,因为基本数据类型的值是不可变的,不需要拷贝。

如果目标对象是对象类型,则进入递归拷贝的过程。首先会判断当前目标对象是否已经被拷贝过(即是否已经在 Map 对象 h 中出现过),如果是,则直接返回已经拷贝过的对象,避免无限递归拷贝。

如果目标对象还没有被拷贝过,则创建一个新的对象或数组 newTarget,具体是数组还是普通对象由目标对象的类型决定。接着,通过 for-in 循环遍历目标对象的所有属性,并将每个属性值递归调用深拷贝函数,将拷贝后的值存储在新的对象或数组 newTarget 中。

最后,将目标对象和新的对象或数组 newTarget 存储在 Map 对象 h 中,以便下次遇到相同的目标对象时可以直接返回已经拷贝过的对象。最后,返回新的对象或数组 newTarget。

总的来说,这个深拷贝函数实现了递归遍历目标对象,将所有属性都进行了拷贝,并且避免了循环引用的问题,是一个比较完备的深拷贝函数实现。

使用weakMap来实现递归(好处,有垃圾回收机制,WeakMap中的键必须是对象,而且当键对象不再被引用时,WeakMap会自动清除)

function deepCopy(target, h = new WeakMap) {
    if (typeof target === 'object') {
      if (h.has(target)) return h.get(target)
      const newTarget = Array.isArray(target) ? [] : Object.create(null)
      for (const key in target) {
        newTarget[key] = deepCopy(target[key], h)
      }
      h.set(target, newTarget)
      return newTarget
    } else {
      return target
    }
}

//

这段代码实现了一个深拷贝函数,与前面的代码相比,使用了 WeakMap 替代了 Map。WeakMap 和 Map 的使用方法类似,但是与 Map 不同的是,WeakMap 中的键必须是对象类型,而且当键对象不再被引用时,WeakMap 会自动清除该键值对,以便垃圾回收。

与前面的代码类似,这个深拷贝函数接受两个参数:要拷贝的目标对象或数组 target,以及一个记录已经拷贝过的对象的 WeakMap 对象 h,默认值为一个新的 WeakMap 对象。

函数的核心逻辑与前面的代码基本一致,不再赘述。区别在于,这个函数使用 WeakMap 来记录已经拷贝过的对象,而不是使用 Map。使用 WeakMap 的好处是可以自动清除不再被引用的对象,避免内存泄漏。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值