• javaScript深拷贝和浅拷贝简单梳理


    在了解深拷贝和浅拷贝之前,我们先梳理一下:

    JavaScript中,分为基本数据类型(原始值)和复杂类型(对象),同时它们各自的数据类型细分下又有好几种数据类型

    基本数据类型

    数字Number 字符串String 布尔Boolean Null Undefined Symbols BigInt

    基本数据类型在内存当中,是存储在栈Stack

    在数据结构当中

    • 栈在内存上的分配的空间生命周期很短,当变量使用完毕,方法执行完成就被释放掉,因此在js当中,变量使用完毕之后,基本就被回收了,
    • 有一个场景比较例外,闭包的情况下,变量是始终存在内存当中不被释放.
    • 栈存储具有先进后出,后进先出的特点: 1,2,3,4,5,6 => 6,5,4,3,2,1

    引用数据类型

    日期Dete,对象Object,数组Array,方法Function, 正则regex,带键的集合:Maps, Sets, WeakMaps, WeakSets

    引用数据类型与堆内存heap的一些关系
    • 在JavaScript中,不允许直接访问堆内存中的位置,不能直接操作对象的堆内存空间。
    • 对象的引用地址是存在栈内存中,在我们的日常编码过程中,操作对象的时候,读取对象的存在栈内存的引用地址而不是在堆中的对象,引用类型的值都是通过引用访问。

    JavaScript中堆内存和栈内存简易示意图例

    image

    下面对于对象的操作,都可以参照上图进行思考

    浅拷贝-深拷贝

    浅拷贝

    只是拷贝了某一层的属性,或者某一层,没有全部拷贝到另外的对象上

    let userInfo = {
      name: "zhangsan",
      age: "29",
      say: function () {
        console.log("hello");
      },
      child: [
        {
          name: "zhangsan01",
        },
      ],
    };
    
    1. 对象解构,只能拷贝第一层对象
    // 对象解构...
    let info = { ...userInfo };
    info.name = "lisi";
    info.child.name = "lisi001";
    info.say();
    
    console.log("userInfo", userInfo);
    console.log("info", info);
    
    userInfo和info中的child.name都改成了---->"lisi001"
    
    
    1. Object.assign() 第一层是深拷贝,二级属性后就是浅拷贝
    let info = {};
    Object.assign(info, userInfo);
    info.name = "lisi";
    info.child.name = "lisi001";
    console.log("userInfo", userInfo);
    console.log("info", info);
    
    
    1. JSON.parse(JSON.stringify());
      对象可以复制,但是当属性是function时,没有复制到新的对象上,因此在日常的开发过程中,涉及到数组对象,使用JSON.parse(JSON.stringify());还是没问题的
    let info = JSON.parse(JSON.stringify(userInfo));
    info.name = "lisi";
    info.child.name = "lisi001";
    console.log("userInfo", userInfo);
    console.log("info", info);
    
    
    1. for in,第一层可以拷贝,第二层在修改的时候,还是使用的引用地址,前后的对象都发生了更改
    let info = {};
    for (let key in userInfo) {
      info[key] = userInfo[key];
    }
    info.name = "lisi";
    info.child.name = "lisi001";
    console.log("userInfo", userInfo);
    console.log("info", info);
    

    浅拷贝小结

    以上浅拷贝方法,有些拷贝只能拷贝第一层,有些可以拷贝多层,
    但是当属性类型是方法时,还是浅拷贝,
    因此我们在开发中,使用浅拷贝,需要注意,同时,出了拷贝function,类似正则,date等数据类型没有一一列举,感兴趣的同学可以自己写一些demo,去校验更为复杂和数据类型更丰富的数据。

    深拷贝

    所有的属性都拷贝到新的对象上

    1. 使用递归遍历每一个属性,在递归遍历的时候,针对每一种数据类型处理和拷贝
    2. lodash深拷贝方法,感兴趣的同学,可以去阅读lodash深拷贝的实现源码

    文档地址:深拷贝cloneDeep https://www.lodashjs.com/docs/lodash.cloneDeep

    1. 更多方法,有待补充

    结尾

    • 当我们操作复杂数据类型的时候,都是在操作栈内存Stack的内存地址,指针指向对象在堆内存heap的数据。

    • 传入的对象是使用对象字面量{}创建的对象还是由构造函数生成的对象

    • 如果对象是由构造函数创建出来的,那么是否要拷贝原型链上的属性

    • 如果要拷贝原型链上的属性,那么如果原型链上存在多个同名的属性,保留哪个

    • 针对的数据类型,属性的数据类型,各自的缺陷,适用的业务场景,自己造轮子or使用原生方法,工具类


    源码地址

    文章个人博客地址:javaScript中深拷贝和浅拷贝梳理

    欢迎关注公众号:程序员布欧,不定期更新一些前端入门文章

    创作不易,转载请注明出处和作者。

  • 相关阅读:
    ASP.NET DataBinder.Eval与 Eval
    TCP为什么是可靠的(怎么保证有效传输的)?
    matlab中hamming窗的 c/c++ 版本的实现
    【Leetcode HOT100】和为 K 的子数组 c++
    【计组】计算机系统体系结构
    2023全网最火的接口自动化框架对比 (建议收藏)
    圣杯布局和双飞翼布局
    景联文科技:高质量数据采集清洗标注服务,助力大语言模型红蓝对抗更加精准高效
    elk日志某个时间节点突然搜索不到了
    C# 将本地图片插入到Excel文件中
  • 原文地址:https://www.cnblogs.com/akari16/p/16193464.html