Javascript 深拷贝的前因后果(深层理解)


前言

关于 JS 的深拷贝,相信不少同学都有所耳闻或者了解吧,那为什么会有深拷贝?深拷贝解决了什么问题?深拷贝的实现逻辑是什么?作为前端面试的高频考点,今天这篇文章就带大家吃透深拷贝,搞懂它的前因后果


前因—浅拷贝

在讲浅拷贝之前,先来了解一下什么是值类型和引用类型,会的同学就当复习一波~

值类型和引用类型

什么是值类型和引用类型?一个例子教大家看懂:
值类型:
在这里插入图片描述
这个大家应该都能理解,比较直观的逻辑,打印的b结果为100。看下面逻辑图加深印象
在这里插入图片描述

值类型都是通过栈进行存储的:

  • 第一步:把a赋值成100
  • 第二步:把b赋值为a,也是等于100
  • 第三步,把a赋值为100,a和b互不影响,b的值仍未100

引用类型:
在这里插入图片描述

a赋值成一个对象age:20,b赋值为a,b.age赋值为21,最后打印a.age的值也为21。看下面逻辑图加深印象:

在这里插入图片描述
这里除了上面的栈,还引入了一个新的概念堆。在计算机的存储中,栈从上往下排列,堆从下往上排列,一般不会重合。来看一下上面例子的存储过程:

  • 第一步:给age赋值成一个等于20的对象,他的key会给一个内存地址一,此时变量a指向的是一个内存地址1,也就是说a里面存储的并不是这个对象,而是存入了内存地址指向这个对象
  • 第二步:a指向内存地址一,b也指向内存地址一,看似a等于age:20,b也等于age:20
  • 第三步:b.age等于21的话,肯定会把下面的对象改为age:21,因为a指向的也是这个地址,所以a.age也是21
    区别: 值类型各自赋值,不会相互干扰;引用类型上面b改变了a也会随之改变

看完了上面,下面给大家上个题,练习练习:

在这里插入图片描述
正确答案是shanghai,跟我们上面第二个例子的逻辑过程一样,这样的过程我们就称之为“浅拷贝”。
那么有没有什么办法能像赋值值类型一样,将引用类型也去以这种方式赋值呢?也就是改变obj2的值,obj1的值不改变。
正是为了解决这个问题,所以有了我们今天的主角——深拷贝

后果—深拷贝

关于深拷贝

  • 会克隆出一个对象,数据相同,但是引用地址不同

上面这句话大家是不是觉得有点抽象,下面我们利用上题obj的例子来带大家实现一下深拷贝:

扫描二维码关注公众号,回复: 13554546 查看本文章

手写深拷贝

先来直接上代码,再给大家分析一波(代码关键在于理解递归):

function deepClone(obj = {
     
     }) {
    
    
    if (typeof obj !== 'object' || obj == null) {
    
    
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }

    // 初始化返回结果
    let result
    if (obj instanceof Array) {
    
    
        result = []
    } else {
    
    
        result = {
    
    }
    }

    for (let key in obj) {
    
    
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
    
    
            // 递归调用!!!
            result[key] = deepClone(obj[key])
        }
    }
	
    // 返回结果
    return result
}

我们直接定义这个深拷贝的函数:

  • 第一步:先进行判断,因为深拷贝针对对象来进行,所以如果obj为空或者不是对象和数组,我们直接返回这个obj
  • 第二步:先初始化结果,然后进行判断,obj instanceof Array是判断它是否为数组,数组则返回数组格式,对象也就返回对象的格式
  • 第三步:进行一个for遍历,遍历对象中的每一个key,obj.hasOwnProperty(key)是保证key为每个对象自己所拥有的属性
  • 第四步:result[key] = deepClone(obj[key]),进行递归调用,因为对象中有的key会嵌套很对层,使用递归保证到判断到每一层的属性
  • 最后就是返回结果

写完之后直接调用这个函数

const obj2 = deepClone(obj1)
console.log(obj1.address.city)

再来看结果,改变obj2的值后,obj1的值并没有发生改变,这样我们的目的就达到了
在这里插入图片描述
我们再来看看深拷贝的实现逻辑图:

在这里插入图片描述

  • 一样的有栈和堆,key值a存储内存地址1,指向对象{ age:20 }
  • b进行深拷贝a,此时会克隆出一个内存地址2,指向的内容与地址1相同,并且b当中存入的也是新生产的内存地址2。所以数据相同,但是引用地址不同。
  • 因为引用的地址不同,所以b改变,a不会变。

今天分享的内容就到这里了,对你有帮助的话点赞支持~有问题可以在下方交流

猜你喜欢

转载自blog.csdn.net/weixin_45745641/article/details/121510217