JavaScript数组对象的浅拷贝与深拷贝(一)深浅拷贝的区别+图解原理

文章详细介绍了JavaScript中数组对象的浅拷贝和深拷贝概念,包括它们的实现原理和区别。浅拷贝仅复制对象的引用,而深拷贝则创建全新的对象副本,避免了原始对象被修改的问题。文中通过代码示例和图解阐述了两种拷贝方式在内存管理和数据处理上的差异,并强调了深浅拷贝在处理引用类型数据时的重要性。
摘要由CSDN通过智能技术生成

知识回调(不懂就看这儿!)

知识专栏专栏链接
JavaScript知识专栏https://blog.csdn.net/xsl_hr/category_12024214.html?spm=1001.2014.3001.5482

有关JavaScript的相关知识可以前往JavaScript知识专栏查看复习!!

场景复现

在程序员的日常开发中,一定离不开数据的分析与处理,无论是使用什么语言进行编程,都会涉及到相应的数据处理。而其中比较常见也很经典的问题便是数据的深浅拷贝

首先解释一下深浅拷贝出错会导致什么样的结果

  • 你发现上一行代码打印出来的值是正确的,但是下一行就不对了,
  • 或者单个的数据打印是正确的,一旦你打印整体的数据,就会不符合要求。
  • 还有很多例子,都是数据的深浅拷贝出错所导致的。

下面我们来从底层原理来学习什么是浅拷贝,什么是深拷贝。👇👇👇

底层知识与原理

1.关于内存(图解)

名词解释
栈内存(stack)自动分配的内存空间,它由系统自动释放
堆内存(heap)动态分配的内存及大小,不一定会自动释放

在这里插入图片描述

2.关于数据类型

名词解释
基本数据类型String, Number, Boolean, undefined, null, Symbol
引用数据类型Object, Array, Function

在JS中,数据类型分为基本数据类型引用数据类型两种

  • 对于基本数据类型来说,它的直接存储在栈内存
  • 而对于引用类型来说,在栈内存中仅仅只存储了一个引用,而真正的数据存储在堆内存中

3.关于赋值的原理

赋值是将某一数值或对象赋给某个变量的过程

基本数据类型的赋值
代码示例:

var a = 1;
var b = a;
console.log(b)  // 1

a = 2;
console.log(b)  // 1

b = 3;
console.log(a) // 2
  • 基本数据类型:我们可以发现,对于基本的数据而言,当我们进行赋值时,系统会自动对变量b在栈内存中开辟一块新的内存进行存储变量a与变量b的值互不影响,相互独立
  • 我们可以画个图来辅助理解:
    在这里插入图片描述

引用数据类型的赋值
代码示例:

 let a2 = { a:1, b:'Trist' };
 let b2 = a2;
console.log(b2) // {a: 1, b: "Trist"}

 b2.a = 2;
console.log(a2.a) // 2
  • 引用数据类型: 通过对于引用数据类型的实验,我们发现与基本数据类型不同的是,两个变量之间会相互干扰。为什么会出现这种现象呢?其实是因为引用数据类型存储在堆内存中,当进行赋值时,系统为变量b2传入了变量a2指向堆内存中地址的指针实际上他们俩指向的是同一个对象,所以当第二个变量的值改变的时候,第一个变量的值也会改变。
  • 同样的我们可以画个图辅助理解:
    在这里插入图片描述

注意深浅拷贝只针对于引用类型。因为只有引用数据类型才会出现变量相互干扰和内存地址的问题。

深拷贝与浅拷贝

在这里插入图片描述

浅拷贝实现原理(图解)

  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身新旧对象还是共享同一块内存。(只复制对象空间而不复制资源)
  • 深拷贝另外创造一个一模一样的对象,新对象跟原对象不共享内存修改新对象不会改到原对象

实现原理:创建一个拷贝的方法 clone(),通过遍历传入对象的键名及键值然后赋值给一个空对象,这样就完成了对原对象的浅拷贝。

代码示例:

        function clone(obj) {
            var cloneObj = {};
            for(var key of Object.keys(obj)) {
                cloneObj[key] = obj[key];
            }
            return cloneObj;
        }
        
        var a3 = {
            a: 1,
            b: 'Trist',
            c: { d: 1 }
        }
        var b3 = clone(a3)
        console.log(b3)  // {a: 1,b: "Trist",c: {d: 1}}

        a3.a = 2;
        console.log(b3.a) // 1

        b3.b = '张三',
        console.log(a3.b) // Trist

        b3.c.d = 2;
        console.log(a3.c.d) // 2

我们可以发现,当我们拿到a3的浅拷贝后,对于对象中的基本数据类型而言,相互之间是互不影响的,而对于引用数据而言,相互之间会互相干扰。

对于浅拷贝的理解:

  • 浅拷贝只复制了原对象最外层的属性,也就是拷贝了基本数据类型的数据,而对于引用数据类型而言,它仅仅是复制了其引用指向的地址还是原对象的地址
  • 因此我们在开发中碰到的赋值出现问题,原因可能就是使用了浅拷贝,并没有将新的数据存入新的地址,达到深层拷贝的效果。

图解
在这里插入图片描述

注意
通过对浅拷贝的认识,如果我们要实现对深层级的数据进行的操作不仅仅是单纯的引用,则需要对原对象内所有的属性值进行递归遍历,这就是相对于浅拷贝而言更深层的深拷贝了。

深拷贝实现原理(图解)

实现原理:首先进行遍历,判断原对象内的属性是否还有对象以及空值null,若有则判断对象是否为数组,有则赋值空数组,无则赋值空对象,然后进行递归。

代码示例:

        function deepClone(obj, cloneObj) {
            var cloneObj = cloneObj || {};
            for(var i in obj) {
                // 通过遍历判断属性是否为引用类型,此处注意null因为历史遗留bug通过typeof输出为object
                if(typeof obj[i] === 'object' && typeof obj[i] !== null) {
                    // 判断引用值是否为数据 obj[i] instanceof Array
                    cloneObj[i] = (obj[i].constructor === Array) ? [] : {};
                    // 进行递归
                    deepClone(obj[i], cloneObj[i]);
                }else {
                    cloneObj[i] = obj[i];
                }
            }
            return cloneObj;
        }

        var b4 = deepClone(a4,b4);
        console.log(b4) 

        a4.a = 2;
        console.log(b4.a) // 1

        b4.b = '张三',
        console.log(a4.b) // Trist

        console.log(a4.c) // 1
        console.log(b4.c) // 1
        b4.c.d = 2;
        console.log(a4.c) // 1
        console.log(b4.c) // 2

        console.log(a4.size) // [1, 2, 3]
        console.log(b5.size) // [1, 2, 3]
        b5.size.push(4,5,6)
        console.log(a4.size) // [1, 2, 3]
        console.log(b5.size) // [1, 2, 3, 4, 5, 6]

我们可以发现,不管是原对象内的基本数据类型,还是对象、数组,我们在进行属性的修改添加时,发现他们都各自独立并且互不影响。

对于深拷贝的理解:

  • 深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突。

图解
在这里插入图片描述


以上就是关于JavaScript深拷贝和浅拷贝的底层原理分析与介绍,配有详细的代码示例和图文讲解,相信看完这篇博客的小伙伴们已经对深浅拷贝有了一定的了解了。那么下期文章我们来深入介绍深浅拷贝的方法

在这里插入图片描述


下期文章将介绍JavaScript数组对象浅拷贝和深拷贝的方法~
感兴趣的小伙伴可以订阅本专栏,方便后续了解学习~
觉得这篇文章有用的小伙伴们可以点赞➕收藏➕关注哦~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dorable_Wander

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

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

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

打赏作者

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

抵扣说明:

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

余额充值