Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
深拷贝与浅拷贝的区别是什么?如何实现深拷贝?_创想鸟

深拷贝与浅拷贝的区别是什么?如何实现深拷贝?

深拷贝会递归复制对象所有嵌套属性,确保新旧对象完全独立,而浅拷贝仅复制引用,导致修改相互影响;常用深拷贝方法包括JSON.parse(JSON.stringify(obj))、递归函数处理循环引用和特殊对象,或使用Lodash的_.cloneDeep()及现代API structuredClone()。

深拷贝与浅拷贝的区别是什么?如何实现深拷贝?

浅拷贝仅仅是复制了对象或数组的引用,这意味着新旧变量指向的是内存中的同一块数据,当其中一个修改了内部的复杂类型(比如另一个对象或数组)时,另一个也会随之改变。而深拷贝则不然,它会递归地复制所有嵌套的属性,确保新旧对象在内存中拥有完全独立的存储空间,彼此互不影响。实现深拷贝,通常需要根据对象的结构,逐层、逐属性地进行复制,尤其要关注那些引用类型的数据。

解决方案

理解深拷贝与浅拷贝的核心在于它们对“引用”的处理方式。浅拷贝在遇到对象内部的引用类型属性时,只会复制这个引用本身,而不是引用所指向的实际数据。这就好比你复制了一个文件的快捷方式,而不是文件本身。你通过快捷方式修改了文件内容,原文件自然也变了。深拷贝则不同,它会深入到每一个引用类型属性的内部,将其指向的数据也完整地复制一份,直到所有数据都是原始类型(如数字、字符串、布尔值)为止。这就像你把整个文件都复制了一遍,新旧文件完全独立。

要实现深拷贝,在JavaScript中,最简单粗暴但也最常用的方法是利用

JSON.parse(JSON.stringify(obj))

。这种方法利用了JSON序列化和反序列化的过程,将对象转换为字符串再解析回来,从而切断了所有引用。但需要注意的是,这种方法有其局限性,比如无法处理函数、

undefined

Date

对象(会被转换为字符串)、

RegExp

对象,以及最关键的——循环引用。对于更复杂的情况,我们通常需要编写递归函数,或者借助成熟的第三方库。

浅拷贝的陷阱与潜在风险:为什么理解其行为至关重要?

说实话,我个人在开发中就遇到过好几次因为没搞清楚浅拷贝而引发的“血案”。最典型的场景就是当你从一个配置对象中取出一个子对象,然后直接修改它,结果发现原始的配置对象也跟着变了,这在调试时简直是灾难。

想象一下,你有一个用户设置对象,里面包含一个

theme

子对象,存储着颜色偏好等。如果你只是简单地通过

Object.assign()

或者展开运算符

{...userSettings}

来复制

userSettings

,那么

theme

这个属性其实只是复制了引用。当你尝试修改

copiedSettings.theme.primaryColor = 'blue'

时,原

userSettings.theme.primaryColor

也变成了

blue

。这种隐式修改往往发生在不经意间,尤其是在组件之间传递props,或者在状态管理中处理不可变数据时,如果使用了浅拷贝,就很容易导致数据污染,或者触发不必要的重新渲染。

这种行为模式,尤其在处理数组嵌套对象时,更让人头疼。比如一个包含多个商品对象的购物车数组,如果你浅拷贝了这个数组,然后修改了其中一个商品的某个属性,那么原始购物车数组里的那个商品也会被修改。这不仅影响了数据的纯洁性,也让程序的行为变得难以预测和维护。理解浅拷贝的本质,是避免这些潜在风险的第一步。

实现深拷贝的策略与考量:从简单到复杂

实现深拷贝,方法多种多样,选择哪种取决于你的具体需求和要处理的数据复杂性。

最简单直接的,正如前面提到的,是

JSON.parse(JSON.stringify(obj))

。它的优点是代码简洁,易于理解,对于只包含数字、字符串、布尔值、null以及普通对象和数组的纯数据对象,它工作得很好。但缺点也同样明显,它会丢失函数、

undefined

Symbol

BigInt

等类型,并且会将

Date

对象转换为ISO格式的字符串,

RegExp

对象会变成空对象。更重要的是,它无法处理循环引用,一旦对象内部存在相互引用的情况,它会直接抛出错误。我个人在处理一些简单的API响应数据时,会图方便用它,但只要数据结构稍微复杂一点,就得另寻他法了。

阿贝智能 阿贝智能

阿贝智能是基于AI技术辅助创作儿童绘本、睡前故事和有声书的平台,助你创意实现、梦想成真。

阿贝智能 17 查看详情 阿贝智能

JSON

方法不够用时,我们通常会考虑手写一个递归函数。这需要我们遍历对象的每一个属性,判断其类型。如果是原始类型,直接赋值;如果是对象或数组,则递归调用自身。这里有一个基本的JavaScript实现思路:

function deepClone(obj, hash = new WeakMap()) {  if (obj === null || typeof obj !== 'object') {    return obj;  }  // 处理循环引用  if (hash.has(obj)) {    return hash.get(obj);  }  let cloneObj;  // 处理日期对象  if (obj instanceof Date) {    cloneObj = new Date(obj);  }   // 处理正则表达式  else if (obj instanceof RegExp) {    cloneObj = new RegExp(obj);  }  // 处理Map、Set等其他特殊对象  // else if (obj instanceof Map) { ... }  // else if (obj instanceof Set) { ... }  // ...  else {    cloneObj = Array.isArray(obj) ? [] : {};  }  hash.set(obj, cloneObj); // 存储已克隆的对象,防止循环引用  for (let key in obj) {    // 确保只复制对象自身的属性,不包括原型链上的    if (Object.prototype.hasOwnProperty.call(obj, key)) {      cloneObj[key] = deepClone(obj[key], hash);    }  }  return cloneObj;}

这个递归函数需要考虑很多细节,比如如何处理

Date

RegExp

Map

Set

等内置对象,以及如何优雅地处理原型链上的属性。最重要的是,它需要一个机制来处理循环引用,否则会陷入无限循环。上面代码中的

WeakMap

就是用来记录已经访问过的对象,避免重复克隆和处理循环引用的。

对于更健壮和全面的深拷贝,很多时候我们会选择使用成熟的第三方库,比如Lodash的

_.cloneDeep()

。这些库经过了大量的测试和优化,能够处理各种复杂的边缘情况,包括循环引用、特殊对象类型、不可枚举属性等,用起来省心省力。在生产环境中,如果不是对性能有极致要求且能精准控制数据结构,我个人更倾向于使用这样的库。

优化深拷贝性能与应对特殊场景:循环引用与特殊对象

深拷贝并非没有代价,尤其是在处理大型或深度嵌套的对象时,其性能开销是需要考虑的。

JSON.parse(JSON.stringify(obj))

虽然代码简洁,但其内部的序列化和反序列化过程本身就是耗时操作,对于超大对象,性能瓶颈会非常明显。手写递归函数虽然灵活,但如果实现不当,也可能效率低下。

循环引用是一个深拷贝的经典难题。当一个对象A引用了对象B,而对象B又引用了对象A时,就形成了循环引用。如果深拷贝函数没有处理机制,它会无限递归下去,最终导致栈溢出。前面提到的

WeakMap

Map

就是解决这个问题的有效方法:在克隆一个对象之前,先检查它是否已经被克隆过。如果已经克隆过,就直接返回之前克隆的副本,而不是再次递归。这就像给每个已经处理过的对象打上一个“已访问”的标记。

特殊对象的处理也是深拷贝的另一个难点。除了前面提到的

Date

RegExp

,还有

Map

Set

Promise

Error

对象,甚至自定义类的实例。一个通用的深拷贝函数需要针对这些类型进行专门的判断和处理。例如,对于

Map

Set

,需要遍历它们的成员并递归克隆;对于函数,通常是直接复制引用(因为函数是行为,而非数据,深拷贝函数本身意义不大);对于自定义类的实例,可能需要调用其构造函数并逐一复制属性,甚至考虑原型链上的属性。

值得一提的是,现代浏览器和Node.js环境中,已经有了

structuredClone()

这个API,它实现了结构化克隆算法,能够非常高效且正确地处理大部分复杂类型,包括循环引用、

Date

RegExp

Map

Set

ArrayBuffer

等。如果你的目标环境支持这个API,那无疑是实现深拷贝的最佳选择,它比手写递归函数更健壮,比

JSON

方法更全面,性能也通常更好。当然,对于一些老旧环境的兼容性考虑,手动实现或引入第三方库依然是必要的。

以上就是深拷贝与浅拷贝的区别是什么?如何实现深拷贝?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/215706.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
淘宝手机以旧换新的运费谁出?如何操作?需按照流程保障自身权益。
上一篇 2025年11月3日 14:44:03
laravel怎么使用whereHas对关联模型进行查询过滤_laravel whereHas关联模型查询过滤方法
下一篇 2025年11月3日 14:44:06

相关推荐

  • Linux查看系统日志的常用命令

    答案是查看Linux日志需综合使用journalctl、dmesg、tail、grep等工具。journalctl用于systemd系统集中查询服务及内核日志,支持时间、优先级、字段等多维度过滤;dmesg专注内核启动与硬件问题;tail -f实时监控日志动态;cat、grep、less结合正则和管…

    用户投稿 2026年9月21日
    000
  • Java中设计可扩展类的技巧与经验

    设计可扩展类应优先组合而非继承,通过接口解耦;明确开放protected扩展点并封闭关键逻辑;提供详细文档说明扩展规则;谨慎处理状态与初始化,避免构造器中调用可重写方法;多数场景推荐接口与组合,必要时才允许继承。 在Java中设计可扩展类时,核心目标是让类既能满足当前需求,又便于未来被安全、可控地继…

    2026年9月21日
    100
  • mysql如何实现后台管理系统

    答案:基于MySQL的%ignore_a_1%需设计用户、权限、日志等表结构,通过后端语言实现安全的CRUD接口与JWT认证,前端展示数据并控制权限,确保系统安全稳定。 实现一个基于 MySQL 的后台管理系统,核心是构建一个安全、稳定、可扩展的系统架构,将数据库作为数据存储层,配合后端语言和前端界…

    2026年9月21日
    000
  • 如何为VSCode设置自定义的代码高亮颜色?

    答案:通过settings.json中的editor.tokenColorCustomizations可自定义VSCode代码高亮颜色,支持全局或特定主题下修改关键字、字符串等元素颜色,结合textMateRules和作用域精确控制,提升代码可读性。 为 VSCode 设置自定义的代码高亮颜色,可以…

    2026年9月21日
    000
  • 百度浏览器自动跳转怎么办 百度浏览器页面跳转广告拦截方法

    百度浏览器自动跳转通常由恶意软件或设置被篡改引起,需检查浏览器设置、清除异常插件、修复快捷方式与注册表,并使用安全软件扫描清理,同时启用广告拦截与隐私保护功能以彻底解决问题。 百度浏览器出现自动跳转,通常不是浏览器本身的问题,而是由恶意软件、插件或设置被篡改导致的。解决这个问题需要从多个方面入手,检…

    2026年9月21日
    100
  • 压力测试(Benchmark)Swoole服务的工具与方法

    进行swoole服务的压力测试是为了确保服务在高负载下稳定运行。1. 选择工具:apache jmeter、wrk、locust。2. 使用方法:jmeter通过脚本配置,wrk通过命令行,locust通过python脚本。3. 注意事项:环境隔离、数据监控、脚本设计。4. 优化点:内存泄漏、连接池…

    2026年9月21日
    000
  • vivo浏览器如何开启硬件加速提升流畅度_vivo浏览器开启硬件加速提升浏览体验的方法

    开启硬件加速可改善vivo手机浏览器卡顿,首先在浏览器设置中查找并开启“硬件加速”功能;若无此选项,可进入系统“开发者选项”,启用“强制进行GPU渲染”;同时建议检查系统更新,确保系统版本最新以保障功能兼容性。 如果您在使用vivo手机内置浏览器时遇到页面加载缓慢或动画卡顿的情况,可能是由于硬件加速…

    2026年9月21日
    000
  • 怎么弄微信公众号_微信公众号注册与功能配置教程

    怎么弄微信公众号_微信公众号注册与功能配置教程怎么弄微信公众号_微信公众号注册与功能配置教程怎么弄微信公众号_微信公众号注册与功能配置教程怎么弄微信公众号_微信公众号注册与功能配置教程

    答案:注册微信公众号需先确定账号类型,订阅号适合内容发布,服务号侧重功能服务,个人注册仅能选订阅号,企业可选服务号并需认证;注册后需配置自定义菜单、自动回复和欢迎语以提升用户体验。 微信公众号的注册与功能配置,说到底,就是把你的内容或服务,通过微信这个巨大的平台,有效地触达目标用户。这过程不复杂,但…

    2026年9月21日 用户投稿
    100
  • 在Java中多态是如何通过虚方法实现的

    多态通过动态方法调度实现,JVM利用虚方法表(vtable)在运行时根据对象实际类型确定方法调用。Java中除private、static、final方法和构造器外均为虚方法,子类重写方法后其vtable指向新实现,调用时JVM通过对象类型查找vtable定位具体方法。如Animal a = new…

    2026年9月21日
    000
  • 谷歌浏览器图片无法显示怎么办 谷歌浏览器图片加载失败修复方法

    首先检查浏览器图片显示设置是否允许,确认无误后清除缓存和Cookie数据,接着排查扩展程序干扰,最后更新浏览器并检查硬件加速设置。 谷歌浏览器图片加载不出来,通常不是大问题,多数情况通过几个简单操作就能解决。下面列出几种常见且有效的排查方法。 检查图片显示设置 最直接的原因可能是浏览器被设置为阻止图…

    2026年9月21日
    000
  • 如何配置VSCode来完美支持Vue.js开发?

    安装Volar、TypeScript Vue Plugin、ESLint和Prettier扩展,禁用Vetur,在settings.json中配置vetur.enabled为false,设置ESLint保存时自动修复并指定Prettier为默认格式化工具,关联.vue文件语言,启用TypeScrip…

    2026年9月21日
    000
  • 利用蝴蝶号搭建多账号无人直播系统的完整方案

    利用蝴蝶号搭建多账号无人直播系统的完整方案利用蝴蝶号搭建多账号无人直播系统的完整方案利用蝴蝶号搭建多账号无人直播系统的完整方案利用蝴蝶号搭建多账号无人直播系统的完整方案

    搭建多账号无人直播系统并非一键操作,而是通过“蝴蝶号”实现自动化流程。首先,“蝴蝶号”负责多账号的生命周期管理,包括登录、状态维护、ip代理分配和设备指纹模拟;其次,内容调度系统决定直播内容及播放时间,可为预录视频或动态生成流;再次,推流引擎将内容实时推送至平台,推荐使用ffmpeg结合python…

    2026年9月21日 用户投稿
    100
  • MySQL数据库日志审计与合规性实现_保护敏感数据与满足法规需求

    MySQL数据库日志审计与合规性实现_保护敏感数据与满足法规需求MySQL数据库日志审计与合规性实现_保护敏感数据与满足法规需求MySQL数据库日志审计与合规性实现_保护敏感数据与满足法规需求MySQL数据库日志审计与合规性实现_保护敏感数据与满足法规需求

    mysql日志审计是合规性的基石,因为它提供了数据库操作的完整证据链,记录用户身份、操作类型和时间戳等关键信息,满足gdpr、hipaa等法规要求,并支持事后追溯与事前震慑。1. mysql自身提供错误日志、通用查询日志、慢查询日志和二进制日志,其中通用查询日志记录所有sql语句,二进制日志用于数据…

    2026年9月21日 用户投稿
    100
  • 谷歌浏览器官方在线访问 最新版Chrome官网登录

    谷歌浏览器官方在线访问入口是https://www.google.cn/chrome/,提供简洁界面、跨设备同步、高效内核、安全防护和丰富扩展生态。 谷歌浏览器官方在线访问入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来最新版Chrome官网登录地址,想要获取纯净浏览体验的网友一起随小…

    2026年9月21日
    200
  • Java Collections.singletonList如何创建单元素集合

    Collections.singletonList(T item) 返回只含一个元素的不可变列表,传入指定对象后生成轻量级只读集合,适用于需高效传递单元素场景。该列表禁止修改操作,否则抛出异常,允许 null 元素,内部优化减少内存开销,常用于 API 参数传递或流处理中的临时数据构造。 Java …

    2026年9月21日
    100
  • win8怎么更改锁屏壁纸_Win8锁屏壁纸修改方法

    首先通过电脑设置更换锁屏壁纸,进入“锁屏界面”选择图片或浏览自定义图片;其次可通过控制面板跳转至电脑设置完成相同操作;最后可启用幻灯片放映功能,添加文件夹实现锁屏背景自动轮换。 如果您希望个性化您的Windows 8设备,更改锁屏壁纸是一个简单而有效的方式。系统提供了多种途径来替换默认的锁屏背景图片…

    2026年9月21日
    100
  • JavaScript中的模块联邦如何实现微前端的代码共享?

    模块联邦通过运行时动态加载实现微前端代码共享,无需打包公共依赖。使用 ModuleFederationPlugin 配置 name、remotes、exposes 和 shared,使应用可暴露或引入远程模块,支持组件、工具函数及状态管理共享,提升复用性并减少冗余。 模块联邦通过在构建时让不同应用直…

    2026年9月21日
    200
  • 如何系统学习蝴蝶号无人直播运营的核心知识

    如何系统学习蝴蝶号无人直播运营的核心知识如何系统学习蝴蝶号无人直播运营的核心知识如何系统学习蝴蝶号无人直播运营的核心知识如何系统学习蝴蝶号无人直播运营的核心知识

    要系统学习蝴蝶号无人直播运营的核心知识,首先要理解平台逻辑、制定精细化内容策略、掌握自动化技术并持续进行数据分析与风险控制。具体包括:一是深入研究平台算法和规则边界,确保操作合规;二是构建高质量、多样化且合规的内容素材库,并进行标签化管理;三是选择安全可靠的自动化工具,避免使用违规软件;四是模拟真人…

    2026年9月21日 用户投稿
    300
  • windows怎么清除dns缓存_dns缓存刷新命令详解

    1、刷新DNS缓存可解决网页无法加载或域名解析错误问题。2、通过命令提示符执行ipconfig /flushdns清除系统DNS缓存。3、以管理员身份运行命令提示符并重启DNS Client服务(net stop dnscache和net start dnscache)恢复服务功能。4、在Chrom…

    2026年9月21日
    100
  • Linux interfaces 虚拟网络类型了解01

    Linux interfaces 虚拟网络类型了解01Linux interfaces 虚拟网络类型了解01Linux interfaces 虚拟网络类型了解01Linux interfaces 虚拟网络类型了解01

    在osi模型的定义中,数据链路层和物理层,以及传输层和网络层执行的任务在概念上相似:它们都提供了数据传输的方式,即沿着特定路径将数据从源点传输到目的地的方法。然而,数据链路层和物理层负责跨物理路径的通信服务,而传输层和网络层则提供由多个数据链路组成的逻辑路径或虚拟路径的通信服务。 Bridge操作指…

    2026年9月21日 用户投稿
    100

发表回复

登录后才能评论
关注微信