浅谈完全深拷贝(循环引用,函数,正则,Symbol,Error类型)

普通类型拷贝

直接return型

Number String Boolean Symbol

对于这三种数据类型非引用类型的拷贝,直接return即可

undefined 与 null

为什么将这两者单独拿出来说呢?其实涉及到一个知识点,undefined与null在’=='状态下是相等的,而且该两种数据类型并没有constructor属性。

特殊对象类型

RegExp 与 Date

在这里插入图片描述在这里插入图片描述使用new关键字,传入对象即可。

Error

在这里插入图片描述可以发现,当使用new关键字传入对象时,创建后的对象嵌套了一层Error对象,因此使用Error的message属性。即:
在这里插入图片描述

Function

对于函数类型的对象,我们可以返回一个具名函数,并为其绑定this,并在具名函数中返回函数的返回值即可:
在这里插入图片描述其中的参数问题在代码中解决。

普通对象类型与数组类型

递归每一项key,value即可。于是有下列代码:

const completeDeepClone = (target) => {
            // 补全代码
            // undefined与null
            if (target == null) return target
            // Date
            if (target instanceof Date) return new Date(target)
            // 正则
            if (target instanceof RegExp) return new RegExp(target)
            // Error
            if (target instanceof Error) return new Error(target.message)
            // 函数
            if (target instanceof Function) return function proxy(...args) {
                return target.call(this, args)
            }
            // Symbol Number String Boolean
            if (typeof target !== 'object') return target
            // 处理过undefined与null,该处就可直接创建新对象了
            let newObj = new target.constructor()
            for (let key in target) {
                if (target.hasOwnProperty(key)) {
                	// 只剩对象,数组,Set,Map类型,递归引用类型的key value即可
                    newObj[key] = completeDeepClone(target[key])
                }
            }
            return newObj
     }

循环引用

其实到这里并没有完,那就是循环引用的问题。就是当待拷贝对象obj中的某个key的value值为obj时,以上的递归就会一直递归下去,成为死递归了。

最终方案

因此我们可以传入一个WeakMap数据类型,简单介绍一个该数据类型,该数据类型的key必须为引用类型,具有增(add()),删(delete()),改(set()),查(has())四个基本方法,且为弱引用类型。可以最大程度上节省内存。至于详细内容,大家可以借鉴该篇博客JavaScript中的弱引用和强引用

const _completeDeepClone = (target, hash = new WeakMap()) => {
            // 补全代码
	if (target == null) return target
	if (target instanceof Date) return new Date(target)
  	if (target instanceof RegExp) return new RegExp(target)
    if (target instanceof Error) return new Error(target.message)
    if (target instanceof Function) return function proxy(...args) {
    	return target.call(this, args)
    }
    if (typeof target !== 'object') return target
    if (hash.has(target)) return hash.get(target)
    let newObj = new target.constructor()
    hash.set(target, newObj)
    for (let key in target) {
    	if (target.hasOwnProperty(key)) {
       		newObj[key] = _completeDeepClone(target[key], hash)
       	}
    }
    return newObj
    }

思考

其实这种深拷贝方法还有两个缺陷:

  1. 对于不可枚举类型的数据结构,如WeakMap,WeakSet(),arguments类型的数据无法进行深拷贝。
  2. 如果待拷贝对象的key为Symbol类型时,该深拷贝方法也无法达到目的。(尚在思考中,待续)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值