深入学习JS — 赋值、浅拷贝和深拷贝

1、数据类型

1.1 数据类型分类

ECMAScript中的可以分为两大类:

1、基本数据类型:名值存储在栈内存中,包括:Number、String、Boolean、Null、 Undefined。
2、引用数据类型:名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,包括:Object(数组Array和函数function都属于Object)。

深拷贝和浅拷贝的概念只存在于引用类型中,因为基本数据类型会直接把值拷贝给另一个变量,并没有涉及到引用。

1.2 对象分类

第一类对象:属性全是基本数据类型

        var object1 = {
            a: 1,
            b: 2
        };

第二类对象:属性中存在引用数据类型(不包含函数function)

        var object2 = {
            a: 1,
            b: 2,
            c: {
                d: 4
            }
        };

第三类对象:属性中包含引用类型(包括函数function)

        var object3 = {
            a: 1,
            b: 2,
            c: {
                d: 4
            },
            e: function(){
                console.log('this is function e in object3!')
            }
        }

2、赋值

所谓赋值,就是使用" = "。现在使用第一类对象object1。

        var object1 = {
            a: 1,
            b: 2
        };
        var copyObject1 = object1;
        object1.a = 100;
        console.log('改变object1之后的copyObject1',copyObject1);

在这里插入图片描述

可以看到,object1.a = 100;后,copyObject1也会改变,因为它们两个指向同一地址。所以object1 === copyObject1 true。对于第二类和第三类对象来说,结果肯定是二者也会互相影响。

3、浅拷贝

赋值会导致两个对象指向同一地址,二者会互相影响对方,在有的时候,我们并不希望二者之间互相影响。通过Object.assign函数,可以实现浅拷贝。
直接看例子:

        var object1 = {
            a: 1,
            b: 2
        };
        var copyObject1 = Object.assign({},object1);
        object1.a = 100;
        console.log('object1: ',object1);
        console.log('copyObject: ',copyObject1);
        console.log('object1 === copyObject1',object1 === copyObject1)

在这里插入图片描述
可以看到,貌似object1和copyObject1已经没有关系了。但是!事实并非如此,不然为什么叫拷贝呢?
现在我们拷贝第二类对象:

        var object2 = {
            a: 1,
            b: 2,
            c: {
                d: 4
            }
        };
        var copyObject2 = Object.assign({},object2);
        object2.c.d = 100;
        console.log('浅拷贝后的copyObject2: ',copyObject2)
        console.log('object2 === copyObject2',object2 === copyObject2);
        console.log('object2.c === copyObject2.c',object2.c === copyObject2.c);

在这里插入图片描述
object2 === copyObject2 falseobject2.c === copyObject2.c true,可见Object.assign不会将第二次的应用类型拷贝,也就是引用类型数据的引用类型数据属性。所以对于只包含基本数据类型属性的对象,进行浅拷贝就可以达到我们的要求,但是对于多层的复杂对象,只能进行深拷贝来实现解除对象之间的关联。

4、深拷贝

4.1 使用JSON.stringfy和JSON.parse

        var object2 = {
            a: 1,
            b: 2,
            c: {
                d: 4
            }
        };
        var copyObject2 = JSON.parse(JSON.stringify(object2));
        object2.c.d = 100;
        console.log('object2',object2);
        console.log('深拷贝后的copyObject2',copyObject2);
        console.log('object2 === copyObject2',object2 === copyObject2);
        console.log('object2.c === copyObject2.c',object2.c === copyObject2.c);

在这里插入图片描述
JSON.parse(JSON.stringify(object2)) 是存在缺陷的,当遇到第三类对象时,并不会将函数属性拷贝到目标对象中。

        var object3 = {
            a: 1,
            b: 2,
            c: {
                d: 4
            },
            e: function(){
                console.log('this is function e in object3!')
            },
            array: [1,2,3,4]
        }
        console.log(object3);
        object3.e();
        var copyObject3 = JSON.parse(JSON.stringify(object3));
        console.log('深拷贝后的copyObject3',copyObject3);

在这里插入图片描述

4.2 手写递归函数实现深拷贝

        var object3 = {
            a: 1,
            b: 2,
            c: {
                d: 4
            },
            e: function(){
                console.log('this is function e in object3!')
            },
            array: [1,2,3,4]
        }
		console.log('object3: ',object3);
        var copyObject3 = deepCopy(object3);
        console.log('深拷贝后的copyObject3',copyObject3);
        function deepCopy(source) {
           if (typeof source !== 'object') return source
            //判断是对象还是数组
            let res = source.constructor === Array ? [] : {}
            for (var key in source) {
            // hasOwnProperty  这个方法会查找一个对象是否有某个属性,但是不会去查找它的原型链。
                if (source.hasOwnProperty(key)) {
                    //考虑对象属性可能是 undefined 和 null 的情况
                    if (source[key]) {
                        if (source[key].constructor === Object) {
                            res[key] = deepCopy(source[key])
                        } else {
                            res[key] = source[key]
                        }
                    } else {
                        res[key] = source[key]
                    }
                }
            }
            return res
        }

在这里插入图片描述
基本原理就是通过判断对象的属性,如果是引用类型,那么就要继续递归拷贝。当不是引用类型时,直接返回,结束递归。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小绵杨Yancy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值