拷贝的艺术:深拷贝与浅拷贝的区别与应用(上)

在这里插入图片描述

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6
🍨 阿珊和她的猫_CSDN个人主页
🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》
🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》

文章目录

  • 一、引言
    • 介绍深拷贝和浅拷贝的背景
    • 解释为什么需要了解这两种拷贝方式
  • 二、深拷贝的基本概念
    • 解释什么是深拷贝
    • 深拷贝的实现原理
    • 深拷贝的应用场景
  • 三、浅拷贝的基本概念
    • 解释什么是浅拷贝
    • 浅拷贝的实现原理
    • 浅拷贝的应用场景

一、引言

介绍深拷贝和浅拷贝的背景

深拷贝和浅拷贝是在编程中常见的概念,它们用于处理对象的复制。深拷贝和浅拷贝的背景如下:

  • 深拷贝相当于创建了一个新的对象,这个对象的所有内容都和被拷贝的对象一模一样,即两者的修改是隔离的,相互之间没有影响。
  • 浅拷贝也是创建了一个对象,但是这个对象的某些内容(比如A)依然是被拷贝对象的,即通过这两个对象中任意一个修改A,两个对象的A都会受到影响。

在实际应用中,开发者需要根据具体的需求选择适当的拷贝方式,以确保程序的正确性和性能。

解释为什么需要了解这两种拷贝方式

了解深拷贝和浅拷贝的原因如下:

  1. 数据独立性:深拷贝可以确保复制后的对象与原始对象完全独立。当修改其中一个对象时,不会影响到另一个对象。这在处理复杂的数据结构或共享资源时非常重要,避免了意外的副作用和数据不一致。

  2. 性能考虑:浅拷贝通常比深拷贝更高效,因为它只复制了对象的引用,而不是复制对象的所有内容。在一些情况下,如对象包含大量数据或资源时,深拷贝可能会导致性能下降。

  3. 避免循环引用:在一些复杂的数据结构中,对象之间可能存在循环引用。如果使用浅拷贝,可能会导致无限循环或内存泄漏。深拷贝可以避免这种情况的发生,确保对象的复制是安全的。

总之,了解深拷贝和浅拷贝的概念和区别对于编写可靠、高效的代码非常重要。选择适当的拷贝方式可以根据具体的需求和场景来决定,以确保数据的正确性、独立性和性能。

二、深拷贝的基本概念

解释什么是深拷贝

深拷贝是一种拷贝对象的方式,它会创建一个完全独立于原始对象的新对象。深拷贝不仅复制了对象的引用,还复制了对象的所有内部属性和子对象。

在深拷贝过程中,新对象的属性和子对象与原始对象的属性和子对象是完全分离的,它们之间没有任何关联。修改新对象的属性或子对象不会影响原始对象,反之亦然。

深拷贝通常用于确保对象的独立性和数据的安全性。当需要保留原始对象的完整状态,并且在修改新对象时不会对原始对象造成影响时,深拷贝是非常有用的。

要实现深拷贝,通常需要递归地复制对象的所有属性和子对象。这可以通过手动编写拷贝函数或使用一些库(如lodashjQuery)提供的深拷贝方法来完成。

下面是一个使用 JavaScript 实现深拷贝的示例代码:

function deepCopy(source) {
  // 创建一个空对象作为目标对象
  let target = {};

  // 遍历源对象的属性
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      // 如果源对象的属性是对象,则进行递归深拷贝
      if (typeof source[key] === 'object' && source[key] !== null) {
        target[key] = deepCopy(source[key]);
      } else {
        // 否则,直接复制属性的值
        target[key] = source[key];
      }
    }
  }

  return target;
}

// 示例用法
const obj1 = { prop1: 'value1', prop2: { subProp: 'subValue' } };
const copiedObj = deepCopy(obj1);

console.log(obj1 === copiedObj);  // false
console.log(obj1.prop2 === copiedObj.prop2);  // false

在上述示例中,deepCopy函数接受一个源对象作为参数,并返回一个深拷贝后的新对象。它通过递归遍历源对象的属性,并对每个对象属性进行深拷贝,确保创建的新对象与源对象完全独立。

需要注意的是,深拷贝可能会消耗更多的内存和时间,并且对于一些特殊类型(如函数、循环引用等)的对象可能无法进行深拷贝。在实际应用中,需要根据具体情况选择是否使用深拷贝。

深拷贝的实现原理

深拷贝的实现原理是在进行拷贝时,不仅复制对象本身,还会递归地复制对象内部所有的引用对象。即深度克隆了所有引用类型的属性,创建了一个完全独立的新对象,该对象与原始对象没有任何关联,对新对象和原始对象的修改互不影响。

在深拷贝中,新对象和原始对象分别对应不同的内存区域,它们之间不存在引用关系,因此修改其中一个对象不会影响到另一个对象。实现深拷贝有多种方式,如通过实现Cloneable接口和重写clone()方法、通过序列化和反序列化对象等。

深拷贝的应用场景

深拷贝主要应用于以下场景:

  1. 避免对象共享:在一些情况下,需要确保两个对象完全独立,不共享任何内部状态。深拷贝可以创建对象的副本,使得修改副本不会影响原始对象。

  2. 数据保护:当需要对一个对象进行修改时,为了避免意外修改原始对象,可以使用深拷贝创建一个副本进行操作。

  3. 缓存和持久化:深拷贝可以用于将对象缓存到其他地方,或者将对象序列化到磁盘或数据库中进行持久化。

  4. 传递对象:在函数参数传递或在不同模块之间传递对象时,使用深拷贝可以确保传递的是对象的独立副本,而不是原始对象的引用。

  5. 多线程编程:在多线程环境中,为了避免竞态条件和数据不一致性,有时需要使用深拷贝来创建线程安全的对象副本。

在这里插入图片描述

需要注意的是,深拷贝会创建对象的完整副本,包括所有嵌套对象和引用对象。这可能会导致性能消耗和内存开销的增加,因此在使用深拷贝时需要考虑性能和资源的影响,并根据实际需求进行选择。

三、浅拷贝的基本概念

解释什么是浅拷贝

浅拷贝是一种拷贝对象的方式,它只复制了对象的第一层属性,而不复制嵌套对象或引用对象。

在浅拷贝过程中,新对象的属性将指向原始对象对应属性的引用,而不是创建新的嵌套对象或引用对象。这意味着,如果修改新对象的属性,原始对象的相应属性也会受到影响,因为它们共享同一个嵌套对象或引用对象。

以下是一个使用 JavaScript 实现浅拷贝的示例代码:

function shallowCopy(source) {
  let target = {};
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      target[key] = source[key];
    }
  }
  return target;
}

// 示例用法
const obj1 = { prop1: 'value1', prop2: { subProp: 'subValue' } };
const copiedObj = shallowCopy(obj1);

console.log(obj1 === copiedObj);  // false
console.log(obj1.prop2 === copiedObj.prop2);  // true

在上述示例中,shallowCopy函数创建了一个新的对象target,并将source对象的属性逐个复制到target中。然而,由于使用的是浅拷贝,嵌套对象prop2并没有被复制,而是共享了原始对象的引用。

浅拷贝通常比深拷贝更高效,因为它不需要递归复制嵌套对象。但在处理嵌套对象时需要特别小心,因为修改新对象的嵌套属性可能会影响原始对象。如果需要完全独立的副本,通常使用深拷贝更合适。

浅拷贝的实现原理

浅拷贝的实现原理是创建一个新的对象,然后将原始对象的属性逐个复制到新对象中。然而,对于嵌套对象或引用对象,浅拷贝只会复制引用,而不是创建新的嵌套对象或引用对象。

以下是一个使用 JavaScript 实现浅拷贝的示例代码:

function shallowCopy(source) {
  let target = {};
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      target[key] = source[key];
    }
  }
  return target;
}

// 示例用法
const obj1 = { prop1: 'value1', prop2: { subProp: 'subValue' } };
const copiedObj = shallowCopy(obj1);

console.log(obj1 === copiedObj);  // false
console.log(obj1.prop2 === copiedObj.prop2);  // true

在上述示例中,shallowCopy函数创建了一个新的对象target,并将source对象的属性逐个复制到target中。然而,由于使用的是浅拷贝,嵌套对象prop2并没有被复制,而是共享了原始对象的引用。

浅拷贝通常比深拷贝更高效,因为它不需要递归复制嵌套对象。但在处理嵌套对象时需要特别小心,因为修改新对象的嵌套属性可能会影响原始对象。如果需要完全独立的副本,通常使用深拷贝更合适。

浅拷贝的应用场景

浅拷贝主要适用于以下场景:

  1. 数据备份:在需要对数据进行备份时,可以使用浅拷贝来创建原始数据的副本,以防止意外修改原始数据。

  2. 数据传递:当需要将数据传递给其他函数或模块时,可以使用浅拷贝来避免共享嵌套对象或引用对象导致的数据修改。

  3. 缓存和暂存:浅拷贝可以用于创建对象的缓存或暂存副本,以减少重复计算或资源消耗。

在这里插入图片描述

需要注意的是,浅拷贝适用于不需要修改嵌套对象或引用对象的情况。如果需要对嵌套对象进行独立修改,通常使用深拷贝更合适。在实际应用中,根据具体需求选择适当的拷贝方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/249561.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚拟电厂 能源物联新方向

今年有多热?据上海市气象局官微消息,5月29日13时09分,徐家汇站气温达36.1℃,打破了百年来的当地5月份气温*高纪录。不仅如此,北京、四川、江西、湖南、广东、广西等地也频频发布高温预警。 伴随着居民用电急剧攀升&am…

LED 底层原理 和 GPIO引脚、寄存器操作

目录 LED 原理 LED 的驱动方式 普适的 GPIO 引脚操作方法 GPIO 寄存器操作 LED 原理 当我们学习 C 语言的时候,我们会写个 Hello 程序。 那当我们写 ARM 程序,也该有一个简单的程序引领我们入门,这个程序就是点亮 LED。 我们怎样去点亮…

Java 中 IO 流

目录 前言 1. 字节流(Byte Streams): 1.1 输入字节流: 1.2 输出字节流: 2. 字符流(Character Streams): 2.1 输入字符流: 2.2 输出字符流: 3. 转换流&…

如何一键生成多个文件二维码?批量文件二维码制作技巧

文件能批量生成二维码吗?现在的二维码用途范围越来越广,比如常见的有图文、文件、问卷、音频或者视频等内容生成二维码图片,扫码查看内容。那么当需要将很多的文件每个都单独生成一个二维码时,有没有比较简单快捷的操作方法吗&…

SELinux介绍

本章主要介绍在RHEL8中如何使用 SELinux。 了解什么是 SELinux了解 SELinux 的上下文配置端口上下文了解SELinux的布尔值了解SELinux的模式 在 Windows系统中安装了一些安全软件后,当执行某个命令时,如果安全软件认为这个命令对系统是一种危害&#…

二维差分详解

前言 上一期我们分享了一维差分的使用方法,这一期我们将接着上期的内容带大家了解二位差分的使用方法,话不多说,LET’S GO!(上一期链接) 二维差分 二维差分我们可以用于对矩阵区间进行多次操作的题。 二维差分我们还…

使用国内镜像源安装opencv

在控制台输入命令: pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 验证安装: step 1: 打开终端;step 2: 输入python,进入Python编译环境;step 3: 粘贴…

LT8711HE方案《任天堂Switch底座方案》

LT8711HE Type-c转HDMI方案 LT8711HE是高性能的Type-C/DP1.2转HDMI2.0转换器,设计用于连接 USB Type-C 源或 DP1.2 源到 HDMI2.0 接收器。该LT8711HE集成了符合 DP1.2 标准的接收器和符合 HDMI2.0 标准的发射器。此外,两个 CC 控制器是包括用于 CC 通信以…

20.Java程序设计-基于SSM框架的安卓掌上校园生活系统的设计与实现

摘要: 随着移动互联网技术的快速发展,校园生活信息化成为提高学校管理效率、方便学生生活的关键。本研究以基于SSM(Spring Spring MVC MyBatis)框架的技术体系为基础,致力于设计与实现一款功能强大、高效稳定的安卓…

手动添加Git Bash Here到右键菜单(超详细)

通过WindowsR快捷键可以打开“运行窗口”,在“窗口”中输入“regedit”,点击“确定”打开注册表。 依次进入HKEY_CLASSES_ROOT —-》 Directory —-》Background —-》 shell 路径为Computer\HKEY_CLASSES_ROOT\Directory\Background\shell 3.在“s…

来聊聊Spring的循环依赖

文章目录 首先了解一下什么是循环依赖简述解决循环依赖全过程通过debug了解Spring解决循环依赖全过程Aservice的创建递归来到Bservice的创建然后BService递归回到了getAservice的doGetBean中故事再次回到Aservice填充BService的步骤 总结成流程图为什么二级就能解决循环依赖问题…

2023年底总结丨5大好用的局域网监控软件

不知不觉间2023年又到结尾了,今年我们服务过很多想要电脑监控软件的客服,也服务了很多想要加密软件的客户。 这一年,我们走得不疾不徐,走得稳而坚定;这一年,我们累积服务超过万计客户;这一年&a…

面试官:这些大学生都会

大家好,我是 JavaPub。 最近有些同学在后台问我,面试总是会遇到被问 Linux 命令的问题,自己就面试个后端开发岗位,怎么这么难呢? 其实 Linux 命令,对于一个后端开发来说,并不是很难&#xff0c…

springcloudalibaba01

整合springcloud 和 springcloudalibaba&#xff0c;&#xff0c;&#xff0c; 版本对应关系 <dependencyManagement><dependencies><!--每个springcloud的工具都有一个版本每个springcloud alibaba的工具都有一个版本统一版本--> <!-- 整合…

spring boot 实现直播聊天室

spring boot 实现直播聊天室 技术方案: spring bootwebsocketrabbitmq 使用 rabbitmq 提高系统吞吐量 引入依赖 <dependencies><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.42&…

广州华锐互动:汽车电子线束加工VR仿真培训与实际生产场景相结合,提高培训效果

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为企业和个人带来了前所未有的便利。在汽车制造行业中&#xff0c;线束加工作为一项关键的生产工艺&#xff0c;其质量直接影响到汽车的性能和安全。因此&#xff0c;…

【UE】在蓝图中修改材质实例的参数的两种方式

目录 方式一、通过“在材质上设置标量/向量参数值”节点实现 方式二、通过“设置标量/向量参数值”节点实现 方式一、通过“在材质上设置标量/向量参数值”节点实现 1. 在材质中设置了两个参数 2. 创建材质实例 3. 创建一个蓝图&#xff0c;对静态网格体赋予材质实例 在事件…

基于虚拟机下的win7系统安装简记

文章目录 安装系统激活win7提示系统保留分区未分配驱动器问题使用win7 Active激活系统根据dns分配的ip地址将网络改为固定ip&#xff0c;然后关闭防火墙&#xff0c;即可完成虚拟机与宿主机互通 安装系统 在虚拟机中找到自己下载win7镜像文件&#xff0c;配置完成后一路next即…

MySQL数据库卸载-Windows

目录 1. 停止MySQL服务 2. 卸载MySQL相关组件 3. 删除MySQL安装目录 4. 删除MySQL数据目录 5. 再次打开服务&#xff0c;查看是否有MySQL卸载残留 1. 停止MySQL服务 winR 打开运行&#xff0c;输入 services.msc 点击 "确定" 调出系统服务。 2. 卸载MySQL相关组…

虚幻学习笔记13—C++静态和动态加载

一、前言 我们在蓝图中可以很方便的添加各种需要的组件&#xff0c;那么在C代码中要如何实现呢。在代码中分静态和动态加载&#xff0c;而无论静态和动态&#xff0c;加载的内容有资源和资源类&#xff0c;资源类通常为带资源的蓝图类。 二、实现 在实现静态或动态加载时&…