• 详解深拷贝,浅拷贝


    目的:深拷贝希望赋值后的变量的变化不会影响到原来的变量

    基础知识要求:

    数据类型

    基本数据类型:number,string ,boolean,null,undefined,bigInt,symbol
    复杂(引用、Object类型)数据类型:object,arry,date,function,regexp
    基本数据类型存储在栈中,复杂数据类型存储在堆中,在栈中只保留复杂数据类型的属性和引用地址

    判断数据类型的方法

    • typeof
      • 使用方法:
        • typeof 10 //‘Number’
        • typeof {}//‘Object’
        • typeof null//‘Object’
          在这里插入图片描述
      • 缺点:typeof null的值为object,无法分辨是null还是object
    • instanceof
      • 使用方法:
        • function instanceof func;//true
        • 123 instanceof Number;//false;
      • 缺点:只能判断对象是否存在目标对象的原型链上,不能判断字面量的基本数据类型

    原型链中的任何属性都会产生值,如何处理到不需要的属性

    • 让你的程序做检查,并丢弃值为函数的属性
    • 使用hasOwnProperty方法。如果对象拥有独有的属性,它将会返回true。hasOwnProperty方法不会检查原型链()。

    浅拷贝:复杂数据类型的存在赋值关系的两个变量指向同一个引用地址
    深拷贝:旧对象指向原来的引用地址,新对象在堆中创建一个新的空间,指向新的引用地址
    浅拷贝原理:

    参考B站up“前端小野森森-2”

    浅拷贝方式1

    const oldObj={
        name:'哈默',
        age:20,
        colors:['orange','green','blue'],
        friend:{
            name:'小夏'
        },
    }
    const newObj=oldObj;
    newObj.name='小野';
    console.log('oldObj',oldObj);
    console.log('newObj',newObj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    解析:oldObj.name和newObj.name的值是一样的,因为是浅拷贝,我们改变了对象的一个值,另一个对象对应的值也会跟着改变;
    当我们不希望出现同步改变的时候,就会用到深拷贝;
    即newObj的值发生改变时,oldObj的值不会改变

    const oldObj={
        name:'哈默',
        age:20,
        colors:['orange','green','blue'],
        friend:{
            name:'小夏'
        },
    }
    function deepClone(obj){
        if( typeof obj !=='object'||obj == null){
            return obj;}
        let result;
        if(obj instanceof Array){
            result= [];
        }else{
            result={};
        };
        for(let key in obj){
            result[key]=obj[key]
        };
        return result;
    }
    const newObj=deepClone(oldObj);
    newObj.name='小野';
    console.log('oldObj',oldObj);
    console.log('newObj',newObj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    但是这种方式的深拷贝,只拷贝了一层,它不会去处理嵌套的对象,如oldObj.friend.name的值
    所以我们不能直接赋值,应该在函数里面应该递归的调用函数本身;完成嵌套对象的值的深拷贝

    for(let key in obj){
        result[key]=deepClone(obj[key])
    }
    
    • 1
    • 2
    • 3

    还有一个优化点是,应该只拷贝原来对象上自身的属性,原来对象原型上的属性不应该拷贝

    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            result[key]=deepClone(obj[key])
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    遗留点: 没有讲循环引用问题
    循环引用解决思路:添加一个参数cache,里面存储处理过的参数,当遇到循环引用时,将cache中存储的信息返回即可

    参考B站up“左耳击水兽”

    1、JSON.parse(JSON.stringify())

    • 优点:二层及以上可以实现深拷贝
    • 缺点
      • 无法拷贝函数
      • 无法拷贝正则
      • 无法拷贝undefined

    2、借助第三方库lodash实现深拷贝

    浅拷贝方式2

    var shallowObj2 = { ...obj1 }
    
    • 1

    浅拷贝实现方式3

    2、Object.assign()

    • 优点
      • 可以拷贝函数
      • 可以拷贝正则
      • 可以拷贝undefined
    • 缺点 :二层及以上无法实现深拷贝

    参考:

    • 书籍《JavaScript 语言精粹(修订版)》
    • CSDN平台博主“晟小明”<身为三本的我就是凭借这些前端面试题拿到百度京东offer的,前端面试题2021及答案>
    • B站up“前端小野森森-2”
    • B站up“左耳击水兽”
  • 相关阅读:
    代码随想录算法训练营Day36 —— 738.单调递增的数字
    【无线传感器】WSN 查找两个节点之间的最短路径并发送数据(Matlab代码实现)
    多线程:什么是虚假唤醒?为什么会产生虚假唤醒?
    pytest自动化测试两种执行环境切换的解决方案
    C++求解一元一次方程——LeetCode 640
    spring5.0源码解析 Aop 03 生成AopProxy对象
    一文读懂VR数字展览会,从沉浸式体验到市场竞争力的全方位提升
    Python自学教程9-python中的if语句,你知道多少?
    Tars-Java网络编程源码分析
    Arduino ESP32/ESP8266 +ST7735 1.8“tft中秋小时钟
  • 原文地址:https://blog.csdn.net/dancria/article/details/126156544