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

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这个框架现在使用量比较小,个人不做深入研究了

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐