首页 > 其他分享 >什么是深拷贝;深拷贝和浅拷贝有什么区别;深拷贝和浅拷贝有哪些方法(详解)

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

时间:2024-06-15 17:31:27浏览次数:13  
标签:obj 哪些 对象 详解 let 引用 拷贝 original

目录

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

二、浅拷贝

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()
let original = { a: 1, b: { c: 2 } };
let shallowCopy = Object.assign({}, original);

original.a = 3;
original.b.c = 4;

console.log(shallowCopy.a) // 1 ; original.a是original的第一层属性,值是一个数字,所以浅拷贝到shallowCopy中还是一个数值,不受original影响

console.log(shallowCopy.b.c) // 4 ; original.b.c是original的第二层属性,第一层属性original.b的值是一个引用类型,浅拷贝只会拷贝引用,所以修改original.b.c也会修改shallowCopy.b.c
使用展开运算符(...)
let original = { a: 1, b: { c: 2 } };
let shallowCopy = { ...original }; // 使用展开运算符进行浅拷贝

original.a = 3;
original.b.c = 4;

console.log(shallowCopy.a) // 1 ; original.a是original的第一层属性,值是一个数字,所以浅拷贝到shallowCopy中还是一个数值,不受original影响

console.log(shallowCopy.b.c) // 4 ; original.b.c是original的第二层属性,第一层属性original.b的值是一个引用类型,浅拷贝只会拷贝引用,所以修改original.b.c也会修改shallowCopy.b.c
使用数组的slice()方法(仅适用于数组)
let originalArray = [1, 2, 3, [4, 5]];
let shallowCopyArray = originalArray.slice();

originArray.push(6);
originArray[3].push(5);


console.log(originalArray);   // 输出: [1, 2, 3, [4, 5, 5], 6] 
console.log(shallowCopyArray); // 输出: [1, 2, 3, [4, 5, 5]]



let originalArray = [1, 2, 3, [4, 5]];
let shallowCopyArray = originalArray.slice();
originArray.push(6);
originArray[3].push(5);
originArray[3] = [4, 5];

console.log(originalArray);   // 输出: [1, 2, 3, [4, 5], 6] 
console.log(shallowCopyArray); // 输出: [1, 2, 3, [4, 5, 5]] 因为 [4, 5]是一个新数组,是将新的引用赋给了originArray[3],并不会直接改变shallowCopyArray[3]的引用

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

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

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

let a = 10; // a是基本数据类型
let b = a;  // b复制了a的值,a和b现在是两个独立的数字

console.log(a === b); // true,因为它们都是数字10

let obj1 = { key: 'value' };
let obj2 = obj1; // obj2复制了obj1的引用

obj2.key = 'new value'; // 修改obj2的key属性

console.log(obj1.key); // 输出 'new value',因为obj1和obj2引用的是同一个对象
console.log(obj1 === obj2); // true,因为它们引用的是同一个对象


let obj3 = { key: 'value' , deep:{a:5 , b:6}};
let obj4 = obj1; // obj2复制了obj1的引用
obj3.deep.a = 6

console.log(obj4.deep.a); //6

三、深拷贝

3.1、什么是深拷贝

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

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

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

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

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

let original = { a: 1, b: { c: 2 } };
let deepCopy = JSON.parse(JSON.stringify(original));

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

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

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

        举个例子:

function deepCopy(obj, hash = new WeakMap()) {
    if (obj === null) return null;
    if (typeof obj !== 'object') return obj;
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    if (hash.has(obj)) return hash.get(obj);

    let result;
    if (Array.isArray(obj)) {
        result = [];
        hash.set(obj, result);
        for (let i = 0; i < obj.length; i++) {
            result[i] = deepCopy(obj[i], hash);
        }
    } else {
        result = Object.create(Object.getPrototypeOf(obj));
        hash.set(obj, result);
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                result[key] = deepCopy(obj[key], hash);
            }
        }
    }
    return result;
}

四、总结

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

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

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

标签:obj,哪些,对象,详解,let,引用,拷贝,original
From: https://blog.csdn.net/RenGJ010617/article/details/139704285

相关文章

  • Arduino单片机详解
    Arduino单片机详解Arduino是一款开源的电子原型平台,广泛应用于各种电子项目和物联网开发。它通过简单易用的硬件和软件,使得电子制造和编程变得更加容易。Arduino的核心是单片机(Microcontroller),它是一个集成了CPU、内存和外设的芯片。下面将详细介绍Arduino单片机的各个方面,包......
  • 虚拟化 之一 详解 jailhouse 架构及原理、软硬件要求、源码文件、基本组件
      Jailhouse是一个基于Linux实现的针对创建工业级应用程序的小型Hypervisor,是由西门子公司的JanKiszka于2013年开发的,并得到了官方Linux内核的支持,在开源社区中获得了知名度和吸引力。Jailhouse  Jailhouse是一种轻量级的虚拟化技术,可以将多个操作系统(或......
  • 哪些产品需要进行EMC测试?
       1.多媒体设备信息技术设备:具有数据和/或电信消息的输入,存储,显示,检索,传输,处理或控制(或组合),并且可能配备有一个或多个通常用于信息传输的端口等功能的设备,如,笔记本电脑等音频设备:具有音频信号的生成,输入,存储,播放,检索,传输,接收,放大,处理,切换或控制(或其组合)等功能的设备,......
  • C# 对象克隆(深拷贝,不引用对象源的内存地址)
    对象克隆拓展方法:///<summary>///深度克隆对象///</summary>///<typeparamname="T">要克隆的类型</typeparam>///<paramname="obj">要克隆的实体</param>///<returns>返回克隆到的实体</returns>publicstaticTClone<......
  • 盲盒App开发时有哪些技术框架可以借鉴
    在开发盲盒App时,技术框架的选择对于应用的性能、稳定性和用户体验都至关重要。以下是几个可以借鉴的技术框架,它们在不同方面提供了优势,并且结合了参考文章中的相关信息:前端技术框架微信小程序框架:优点:微信庞大的用户基数,易于推广和分享;丰富的API接口,可以快速实现各种功能......
  • Cookie、Session、LocalStorage 和 SessionStorage 的区别详解
    前言在前端开发中,数据存储和状态管理是非常重要的内容。常用的存储方式有Cookie、Session、LocalStorage和SessionStorage。本文将详细介绍这四者的区别,帮助开发者更好地理解和选择合适的存储方案。一、Cookie和Session的区别1.什么是Cookie?Cookie是由服务器生成......
  • PDF标准详解(三)—— PDF坐标系统和坐标变换
    之前我们了解了PDF文档的基本结构,并且展示了一个简单的helloworld。这个helloworld虽然只在页面中显示一个helloworld文字,但是包含的内容却是不少。这次我们仍然以它为切入点,来了解PDF的坐标系统以及坐标变换的相关知识图形学中二维图形变换中学我们学习了平面直角坐标系,x......
  • 【BERT】详解BERT
    一、为什么要提出BERT?传统的RNN类模型,包括LSTM,GRU以及其他各种变体,最大的问题在于提取能力不足。在《WhySelf-Attention?ATargetedEvaluationofNeuralMachineTranslationArchitectures》中证明了RNN的长距离特征提取能力甚至不亚于Transformer,并且比CNN强。其主要问题......
  • 传统后端SQL数据层替代解决方案: 内置数据源+JdbcTemplate+H2数据库 详解
    内置数据源我们回顾一下druid数据源的配置方式通过type属性指定数据源的类型导入依赖starter就使用了spring的自动装配功能格式二是在引入druid的依赖的基础上进行的一种配置方式Tomcat内部也可以进行数据源的配置轻量级中最快的数据源对象我们切换德鲁伊连接池......
  • C语言详解(预编译)
    Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎~~......