• 什么是深拷贝;深拷贝和浅拷贝有什么区别;深拷贝和浅拷贝有哪些方法(详解)


    目录

    一、为什么要区别深拷贝和浅拷贝

    二、浅拷贝

    2.1、什么是浅拷贝

    2.2、浅拷贝的方法

    使用Object.assign()

    使用展开运算符(...)

    使用数组的slice()方法(仅适用于数组)

    2.3、关于赋值运算符(=)

    三、深拷贝

    3.1、什么是深拷贝

    3.2、实现深拷贝的三种常见方法

    使用JSON.parse(JSON.stringify(obj))

    使用第三方库,如lodash的cloneDeep()

    手动实现递归函数

    四、总结


    一、为什么要区别深拷贝和浅拷贝

            在JavaScript中,对象和数组是引用类型,这意味着当你将它们赋值给一个变量或者作为函数参数传递时,你实际上是在传递一个指向内存中对象的引用,而不是对象本身的副本。这就涉及到了深拷贝和浅拷贝的概念。

    二、浅拷贝

    2.1、什么是浅拷贝

            浅拷贝只复制对象的第一层属性。也就是说,如果原始对象的属性是基本类型(如数字、字符串、布尔值),那么浅拷贝会复制这些值;但如果属性是引用类型(如数组、对象、函数),那么拷贝的只是引用,而不复制引用指向的内存地址中的数据。

    2.2、浅拷贝的方法

    使用Object.assign()
    1. let original = { a: 1, b: { c: 2 } };
    2. let shallowCopy = Object.assign({}, original);
    3. original.a = 3;
    4. original.b.c = 4;
    5. console.log(shallowCopy.a) // 1 ; original.a是original的第一层属性,值是一个数字,所以浅拷贝到shallowCopy中还是一个数值,不受original影响
    6. console.log(shallowCopy.b.c) // 4 ; original.b.c是original的第二层属性,第一层属性original.b的值是一个引用类型,浅拷贝只会拷贝引用,所以修改original.b.c也会修改shallowCopy.b.c
    使用展开运算符(...)
    1. let original = { a: 1, b: { c: 2 } };
    2. let shallowCopy = { ...original }; // 使用展开运算符进行浅拷贝
    3. original.a = 3;
    4. original.b.c = 4;
    5. console.log(shallowCopy.a) // 1 ; original.a是original的第一层属性,值是一个数字,所以浅拷贝到shallowCopy中还是一个数值,不受original影响
    6. console.log(shallowCopy.b.c) // 4 ; original.b.c是original的第二层属性,第一层属性original.b的值是一个引用类型,浅拷贝只会拷贝引用,所以修改original.b.c也会修改shallowCopy.b.c
    使用数组的slice()方法(仅适用于数组)
    1. let originalArray = [1, 2, 3, [4, 5]];
    2. let shallowCopyArray = originalArray.slice();
    3. originArray.push(6);
    4. originArray[3].push(5);
    5. console.log(originalArray); // 输出: [1, 2, 3, [4, 5, 5], 6]
    6. console.log(shallowCopyArray); // 输出: [1, 2, 3, [4, 5, 5]]
    7. let originalArray = [1, 2, 3, [4, 5]];
    8. let shallowCopyArray = originalArray.slice();
    9. originArray.push(6);
    10. originArray[3].push(5);
    11. originArray[3] = [4, 5];
    12. console.log(originalArray); // 输出: [1, 2, 3, [4, 5], 6]
    13. console.log(shallowCopyArray); // 输出: [1, 2, 3, [4, 5, 5]] 因为 [4, 5]是一个新数组,是将新的引用赋给了originArray[3],并不会直接改变shallowCopyArray[3]的引用

    2.3、关于赋值运算符(=)

            在JavaScript中,赋值运算符(=)本身并不执行浅拷贝或深拷贝。赋值运算符只是将一个值或一个引用赋给一个变量。如果赋值的是一个基本数据类型(如数字、字符串、布尔值),那么赋值运算符会复制这个值。如果赋值的是一个引用类型(如对象、数组、函数),那么赋值运算符会复制这个引用,而不是引用指向的对象本身。

            当使用赋值运算符来处理对象和数组时,没有创建一个新的对象/数组,两个变量指向的是同一个对象/数组,所以不管修改哪一个对象/数组的任何一层的任何一个数据,另外一个都会随之改变。(连浅层/第一层的数值都没有拷贝,完全依赖引用)

    1. let a = 10; // a是基本数据类型
    2. let b = a; // b复制了a的值,a和b现在是两个独立的数字
    3. console.log(a === b); // true,因为它们都是数字10
    4. let obj1 = { key: 'value' };
    5. let obj2 = obj1; // obj2复制了obj1的引用
    6. obj2.key = 'new value'; // 修改obj2的key属性
    7. console.log(obj1.key); // 输出 'new value',因为obj1和obj2引用的是同一个对象
    8. console.log(obj1 === obj2); // true,因为它们引用的是同一个对象
    9. let obj3 = { key: 'value' , deep:{a:5 , b:6}};
    10. let obj4 = obj1; // obj2复制了obj1的引用
    11. obj3.deep.a = 6
    12. console.log(obj4.deep.a); //6

    三、深拷贝

    3.1、什么是深拷贝

            深拷贝会创建一个全新的对象,并且递归地复制所有属性,使得原始对象和拷贝对象完全独立,互不影响。深拷贝后的对象中所有的属性都是新的引用,即使属性是引用类型,也会被完全复制。

            实现深拷贝的方法相对复杂,因为需要递归地复制对象的所有层级。以下是一些常见的实现方式

    3.2、实现深拷贝的三种常见方法

    使用JSON.parse(JSON.stringify(obj))

            这是最简单的一个方法,实际开发中经常会用到,不过虽然简单但有局限性,不能处理函数、undefined、循环引用、特殊对象(如Date、RegExp)等。

    1. let original = { a: 1, b: { c: 2 } };
    2. let deepCopy = JSON.parse(JSON.stringify(original));
    使用第三方库,如lodash的cloneDeep()
    1. let original = { a: 1, b: { c: 2 } };
    2. let deepCopy = JSON.parse(JSON.stringify(original));
    手动实现递归函数

            实现深拷贝的递归函数需要考虑多种情况,包括但不限于:

    • 检测对象是否为基本类型。
    • 处理循环引用。
    • 复制数组和对象。
    • 处理特殊对象(如Date、RegExp)。

            举个例子:

    1. function deepCopy(obj, hash = new WeakMap()) {
    2. if (obj === null) return null;
    3. if (typeof obj !== 'object') return obj;
    4. if (obj instanceof Date) return new Date(obj);
    5. if (obj instanceof RegExp) return new RegExp(obj);
    6. if (hash.has(obj)) return hash.get(obj);
    7. let result;
    8. if (Array.isArray(obj)) {
    9. result = [];
    10. hash.set(obj, result);
    11. for (let i = 0; i < obj.length; i++) {
    12. result[i] = deepCopy(obj[i], hash);
    13. }
    14. } else {
    15. result = Object.create(Object.getPrototypeOf(obj));
    16. hash.set(obj, result);
    17. for (let key in obj) {
    18. if (obj.hasOwnProperty(key)) {
    19. result[key] = deepCopy(obj[key], hash);
    20. }
    21. }
    22. }
    23. return result;
    24. }

    四、总结

            浅拷贝适用于只复制对象的第一层属性,且这些属性不是引用类型。深拷贝适用于需要完全独立的副本,包括对象和数组的嵌套结构。选择哪种拷贝方式取决于你的具体需求和场景。

            意犹未尽?更多精彩前端好文请关注:各种前端问题的技巧和解决方案

            博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

  • 相关阅读:
    uniapp图片加水印
    MySQL 常用函数 2022/09/06
    C语言之const
    1、2快速生成
    Netty 入门
    渗透测试-一次完整的渗透测试流程
    Mysql数据库大数据量的解决方案介绍(三、Mycat中间件分片实战)
    论文阅读笔记(四)——实例分割与掩模R-CNN应用于多摄像机设置中松散的奶牛
    Pandas文件读写操作
    痞子衡嵌入式:聊聊i.MXRT1xxx上第三级启动保障 - SDMMC manufacture模式
  • 原文地址:https://blog.csdn.net/RenGJ010617/article/details/139704285