浅谈Javascript深浅拷贝

1.总述

  在JavaScript中深浅拷贝均针对于引用数据类型。为了验证各种拷贝,准备三层深入结构的Object对象类型数据。

        var obj = {
            level1stu:[
                {name:"frank1", girlFriends:["迪丽肉巴1","古力nong扎1","玛尔扎哈1"]},
                {name:"frank2", girlFriends:["迪丽肉巴2","古力nong扎2","玛尔扎哈2"]},
                {name:"frank3", girlFriends:["迪丽肉巴3","古力nong扎3","玛尔扎哈3"]}
            ],        
            level2stu:[
                {name:"oycat1", girlFriends:["小战1","王九博1","李难峰1"]},
                {name:"oycat2", girlFriends:["小战2","王九博2","李难峰2"]},
                {name:"oycat3", girlFriends:["小战3","王九博3","李难峰3"]}
            ]        
        };

2.由浅入深实现各种拷贝

2.1 浅拷贝

  浅拷贝,顾名思义就是拷贝浅层(浮于表面的东西)。在JavaScript中具体表现为就是仅仅将变量保存的内存地址赋值给另一个变量,也就是说两个变量内保存的值是相同的内存地址,故而两个变量仍旧指向相同的内存地址。所以牵一发而动全身,对一个变量操作,另一个变量指向的内存地址中的值当然跟随发生变化。

        var obj1 = obj
        obj1.level1stu[0].girlFriends[0] = "迪吧哈哈";
        console.log(obj);
        console.log(obj1);

2.2 "深一层"的浅拷贝

  "深一层"的浅拷贝,本质上来说并没有这种拷贝方式,严格来讲这玩意儿应该算是一种失败的深拷贝操作。但是这种带有缺陷的拷贝对于理解深拷贝的具体运作机制有帮助,所以姑且写来感受一下。

        var obj1 = {};
        for (let key in obj) {
            obj1[key] = obj[key];
        }
        obj1.level1stu = 0; //完成深拷贝一层
        console.log(obj);
        console.log(obj1);

代码中能够明显看到,拷贝操作不再是单纯的创建变量-赋值操作。而是通过循环的方式,在obj1对象中不断地使用新变量obj1[key]来接收原对象obj中与之对应每一个对应值obj[key]。可以理解为上面的操作拆分开来的话:

obj1 [ level1stu ]  = obj [ level1stu ];

obj1 [ level2stu ]  = obj [ level2stu ];

这样的确实现了 obj1[ level1stu ] obj [ level1stu ] 两个变量所保存的内存地址不同的目的;

但是在更深一层中: obj1[ level1stu ][0]  obj[ level1stu ][0]、obj1[ level1stu ][1]  obj[ level1stu ][1] 这样对应的变量中所保存的内存地址却仍然相同。仍旧存在牵一发而动全身的现象,也就是说仍旧不算是深拷贝。

        //obj1.level1stu = 0; //完成深拷贝一层
        obj1.level1stu[0].girlFriends = 0; //两层直接gg
        console.log(obj);
        console.log(obj1);

2.3深拷贝

  因为对象的内部嵌套层数有可能是"无限的",因此我们在不清楚究竟会有多少层结构的情况下,递归就是我们解决问题的最好办法。

        function deepCopy(obj){
            
            //判断如果要深拷贝的是对象,就创建空对象,否则创建数组。
            var newObj = Array.isArray(obj) ? [] : {};
            
            //设置递归结束条件,如果不是引用类型就结束
            if(typeof obj === "object"){
                
                //遍历每一个属性
                for (let key in obj) {

                    //如果属性仍旧是引用类型,那就递归
                    //如果属性是基本数据类型,那就直接复制
                    if(typeof obj[key] === "object"){
                        newObj[key] = deepCopy(obj[key]);
                    }else{
                        newObj[key] = obj[key];
                    }
                }
            }
            
            //递归结束,返回生成对象
            return newObj;
        }
        var obj1 = deepCopy(obj);
        obj1.level1stu[0].girlFriends[0] = "迪吧哈哈"
        console.log(obj);
        console.log(obj1);

针对拷贝对象的操作,对原对象不会产生任何影响。不管操作多深的层级数据,都没有问题。

3.总结

  本文没有考虑对象属性中存在相互引用的情况,在相互引用情况下使用递归无疑会造成死循环,需要额外注意。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值