JS实现深拷贝的三种方式

深浅拷贝是面试中经常会被问到的问题,哥们这会帮大家整理一下,浅拷贝不写了,这次主要是深拷贝。
看段代码

let obj = {
        a:1,
        b:{
            c: 1
        },
    }

    let copyObj = obj
    copyObj.a = 2
    console.log(obj, copyObj)

在这里插入图片描述

这就浅拷贝

1.JSON.parse(JSON.stringify(obj))

let copyObj = JSON.parse(JSON.stringify(obj))
    copyObj.a = 2
    console.log(obj, copyObj)

在这里插入图片描述
这样就成功了。
面试官:这种实现方案有什么问题吗?
答:该方法不能解决属性为函数,undefined,循环引用的的情况
上代码,看效果

let obj = {
        a:undefined,
        b:{
            c: function() {
                console.log(1)
            },
            d: null,
            e: new Date(),
            f: new RegExp('\\w+'),
            g: NaN
        },
    }

    let copyObj = JSON.parse(JSON.stringify(obj))
    console.log(obj, copyObj)

在这里插入图片描述
1.原对象中的a、c不见了,undefined、function类型的key会丢失
2.e时间对象,会变成字符串形式
3.RegExp定义的属性会变成 {}
4.NaN 类型会变成 null
还有一个问题: 循环引用

let obj = {
        a:1,
    }
    obj.c = obj
    let copyObj = JSON.parse(JSON.stringify(obj))
    console.log(obj, copyObj)

效果:
在这里插入图片描述
5.无法处理循环引用的问题
结论:这种拷贝方式局限性比较大,但是在日常开发中一般只是拷贝基本的数据类型,个人在开发中用的还是比较多

2.递归

一般我们会这样写

function copy(obj){
        let newobj = null;
        if(typeof(obj) == 'object' && obj !== null){ 
            newobj = obj instanceof Array? [] : {};   
            for(var i in obj){  
                newobj[i] = copy(obj[i])
            }
        }else{
            newobj = obj
        }    
      return newobj;
   }

面试官:递归实现有什么问题吗?
还是循环引用的问题

let obj = {
        a:1,
    }
    obj.a = obj
    let copyObj = copy(obj)
    console.log(obj, copyObj)

在这里插入图片描述
还是会报错
解决:用 WeakMap() 或者Map()记录下对象中的所有对象,并与新创建的对象一一对应,即记录引用关系

let map = new Map(); // WeakMap
    function copy(obj){
        let newobj = null;
        if(typeof(obj) == 'object' && obj !== null){ 
            if (map.get(obj)) {
                newobj = map.get(obj) // 如果不想循环打印 可以设置为null
            } else {
                newobj = obj instanceof Array? [] : {};
                map.set(obj, newobj)   
                for(var i in obj){  
                    newobj[i] = copy(obj[i])
                }
            }
            
        }else{
            newobj = obj
        }    
      return newobj;
   }
     obj.b = obj
    let copyObj = copy(obj)
    console.log(obj, copyObj)

在这里插入图片描述
注意:如果遇到时间对象,正则等类型,需要通过new关键字去创建

3.jQuery.extend() 函数

jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。
第一个参数是boolean类型,表示深浅拷贝,true表示深拷贝,false表示浅拷贝。只有两个参数,那么就把jQuery作为target,把第二个参数的字段赋给target,然后返回target。多于两个参数,把第二个参数作为target,然后把后面的参数的字段赋给target,最后面返回target.

let obj = {
        a:1,
        b: {
            c:2
        }
    }
    let copyObj = {}
    $.extend(true,copyObj, obj);
    copyObj.b = 3
    console.log(obj, copyObj)

在这里插入图片描述
问题:当然如果两拷贝对象中有相同的属性名时,后者的值也会覆盖前者的值,就像这样:

let obj = {
        a:1,
        b: {
            c:2
        }
    }
    let obj2 = {
        a:2,
        d:4
    }

    $.extend(true,obj, obj2);
    console.log(obj, obj2)

在这里插入图片描述

PS:jQuery这个框架现在使用量比较小,个人不做深入研究了

  • 32
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值