javascript 深拷贝和浅拷贝的区别及具体实现方案

一、核心区别

特性浅拷贝深拷贝
复制层级仅复制对象的第一层属性递归复制对象的所有层级属性(包括嵌套对象和数组)
引用关系嵌套对象/数组与原对象共享内存(引用拷贝)嵌套对象/数组与原对象完全独立(值拷贝)
修改影响修改拷贝后的嵌套属性会影响原对象修改拷贝后的任何属性都不会影响原对象
适用场景简单数据结构,无需嵌套独立性复杂数据结构,要求完全独立

二、浅拷贝实现方案

1. 对象浅拷贝
  • Object.assign()
    const obj = { a: 1, b: { c: 2 } };
    const shallowCopy = Object.assign({}, obj);
    
  • 展开运算符(...
    const obj = { a: 1, b: { c: 2 } };
    const shallowCopy = { ...obj };
    
2. 数组浅拷贝
  • Array.prototype.slice()
    const arr = [1, 2, [3, 4]];
    const shallowCopy = arr.slice();
    
  • 展开运算符(...
    const arr = [1, 2, [3, 4]];
    const shallowCopy = [...arr];
    

三、深拷贝实现方案

1. JSON 序列化法

原理:通过 JSON.stringify()JSON.parse() 序列化对象。
优点:简单快捷,适合纯数据对象。
缺点:无法处理函数、undefinedSymbolDateRegExp、循环引用等。

const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
2. 递归深拷贝(手动实现)

原理:递归遍历对象属性,处理所有数据类型。
优点:可自定义逻辑,支持复杂场景。
缺点:需处理边界条件(如循环引用)。

function deepClone(source, hash = new WeakMap()) {// 处理基本类型和 null/undefinedif (source === null || typeof source !== 'object') return source;// 处理循环引用if (hash.has(source)) return hash.get(source);// 处理 Date 和 RegExpif (source instanceof Date) return new Date(source);if (source instanceof RegExp) return new RegExp(source);// 初始化拷贝对象(保持原型链)const target = new source.constructor();hash.set(source, target);// 遍历所有属性(包括 Symbol)Reflect.ownKeys(source).forEach(key => {target[key] = deepClone(source[key], hash);});return target;
}
3. 第三方库实现
  • Lodash(推荐)

    import { cloneDeep } from 'lodash';
    const deepCopy = cloneDeep(obj);
    
  • jQuery

    const deepCopy = $.extend(true, {}, obj);
    

四、特殊场景处理

1. 循环引用

问题:对象属性间接引用自身,导致递归栈溢出。
解决方案:使用 WeakMap 缓存已拷贝对象。

const obj = { a: 1 };
obj.self = obj; // 循环引用
const copy = deepClone(obj); // 递归实现中通过 WeakMap 避免死循环
2. 处理特殊对象
  • Date 对象:通过 new Date(source.getTime()) 重建。
  • RegExp 对象:通过 new RegExp(source.source, source.flags) 重建。
  • Map/Set:遍历并递归拷贝每个元素。
3. 函数拷贝

问题:函数无法被完全拷贝(可能依赖闭包环境)。
解决方案:通过 evalnew Function 重建函数(需谨慎使用)。

五、性能对比与选型建议

方法性能功能完整性安全性
JSON 法低(丢失类型)安全
递归实现需处理边界
Lodash安全

选型建议

  • 纯数据对象且无特殊类型 → JSON 法
  • 复杂对象或需要保留类型 → Lodash 的 cloneDeep
  • 定制化需求 → 手动递归实现

六、验证示例

const origin = { a: 1, b: { c: 2 }, d: new Date(), e: /regex/, f: function() { console.log('test') },g: [1, 2, { h: 3 }]
};
origin.self = origin; // 循环引用const copy = deepClone(origin);// 验证
console.log(copy.b === origin.b); // false(深拷贝成功)
console.log(copy.d instanceof Date); // true(保留类型)
console.log(copy.self === copy); // true(循环引用处理成功)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch对应gpu版本是否可用判断逻辑

# gpu_is_ok.py import torchdef check_torch_gpu():# 打印PyTorch版本print(f"PyTorch version: {torch.__version__}")# 检查CUDA是否可用cuda_available torch.cuda.is_available()print(f"CUDA available: {cuda_available}")if cuda_available:# 打印…

国内无法访问GitHub官网的问题解决

作为一名程序员,在国内访问GitHub官网经常会遇到打开过慢或者访问失败的问题,但通过一些技巧可以改善访问体验。GitHub访问问题的根源在于GitHub官网访问不稳定的主要原因在于DNS解析过程。当我们直接访问github.com时,需要通过DNS服务器将域…

使用 MediaPipe 和 OpenCV 快速生成人脸掩膜(Face Mask)

在实际项目中,尤其是涉及人脸识别、换脸、图像修复等任务时,我们经常需要生成人脸区域的掩膜(mask)。这篇文章分享一个简单易用的小工具,利用 MediaPipe 和 OpenCV,快速提取人脸轮廓并生成二值掩膜图像。 …

【动态导通电阻】GaN功率器件中动态导通电阻退化的机制、表征及建模方法

2019年,浙江大学的Shu Yang等人在《IEEE Journal of Emerging and Selected Topics in Power Electronics》上发表了一篇关于GaN(氮化镓)功率器件动态导通电阻(Dynamic On-Resistance, RON)的研究论文。该文深入探讨了GaN功率器件中动态导通电阻退化的机制、表征方法、建模…

从括号匹配看栈:数据结构入门的实战与原理

在计算机科学的世界里,数据结构是程序员的 “瑞士军刀”,不同的数据结构适用于不同的场景,能高效解决各类问题。其中,栈作为一种简单却强大的数据结构,在很多实际应用中发挥着关键作用。今天,我们就通过一个…

Dubbo(89)如何设计一个支持多语言的Dubbo服务?

设计一个支持多语言的Dubbo服务需要考虑以下几个方面: 服务接口设计:确保服务接口的定义可以被不同语言实现。序列化协议:选择一个支持多语言的序列化协议,例如Protobuf、Thrift、gRPC等。服务注册与发现:确保服务注册…

力扣面试150题--分隔链表

day 39 题目描述 思路 遍历链表,每一个点与值比较,比值小就继续,比值大就放到链表尾部即可 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int…

VSCode 查看文件的本地修改历史

1. 使用时间线视图(Timeline) 新版 VSCode 内置了一个叫 Timeline(时间线) 的功能,可以查看: 本地文件修改记录(包括保存历史)Git 提交历史(如果仓库是 Git 管理的&…

C++学习-入门到精通-【3】控制语句、赋值、自增和自减运算符

C学习-入门到精通-【3】控制语句、赋值、自增和自减运算符 控制语句、赋值、自增和自减运算符 C学习-入门到精通-【3】控制语句、赋值、自增和自减运算符一、什么是算法二、伪代码三、控制结构顺序结构选择结构if语句if...else语句switch语句 循环结构while语句 四、算法详述&a…

父子组件双向绑定

v-model 语法糖实现 vue中我们在input中可以直接使用v-model来完成双向绑定,这个时候 v-model 通常会帮我们完成两件事: v-bind:value的数据绑定@input的事件监听如果我们现在封装了一个组件,其他地方在使用这个组件时,是否也可以使用v-model来同时完成这两个功能呢? 当我…

用Selenium开启自动化网页交互与数据抓取之旅

用Selenium开启自动化网页交互与数据抓取之旅 在当今数字化时代,数据的价值不言而喻,而网页作为海量数据的重要载体,如何高效获取其中的关键信息成为众多开发者和数据爱好者关注的焦点。Selenium这一强大工具,为我们打开了自动化…

VB.net序列化和反序列化的使用方法和实用场景

引言 相信很多初学编程的人都会提出过这个疑问:“既然我的变量可以存在内存之中,那么是否也可以存在硬盘之中呢” 其实我想回答的是,完全可以而且方法不止一种,而今天讲的是序列化最经典的——二进制序列化 由于序列化的部分已…

Android OTA

一、OTA运行原理 Android 平台提供 Google diff arithmetic 差分机制,升级包支持完整升级以及差分升级,OTA 运行原理图如下所示。 1. OTA Server 负责对更新包进行上传,下载以及版本的管理。 2. 开发者在修改 Android 系统后,通…

Untiy基础学习(三)Untiy中编写脚本的基本规则

一、怎么创建脚本 在Project窗口下,右键Create C#Script 即可创建脚本 创建脚本的注意事项 : 1)类名和文件名必须一致,不然不能挂载(因为反射机制创建对象,会通过文件名去找Type) 2)没有特殊需…

VBA宏即根据第一列的内容和第二列的数字,按照数字数量生成对应内容并依次放在第三列、第四列等

打开你的 Excel 工作表。按下 Alt F11 组合键,打开 VBA 编辑器。在 VBA 编辑器中,点击 插入 -> 模块。在模块窗口中,输入以下 VBA 代码: Sub GenerateItems()Dim lastRow As LongDim i As Long, j As LongDim item As String…

深度学习系统学习系列【1】之基本知识

文章目录 说明基础知识人工智能、机器学习、深度学习的关系机器学习传统机器学习的缺陷选择深度学习的原因深度学习的关键问题深度学习的应用深度学习的加速硬件GPU环境搭建主流深度学习框架对比 说明 文章属于个人学习笔记内容,仅供学习和交流。内容参考深度学习原…

论文笔记-基于多层感知器(MLP)的多变量桥式起重机自适应安全制动与距离预测

《IET Cyber-Systems and Robotics》出版山东大学 Tenglong Zhang 和 Guoliang Liu 团队的研究成果,文章题为“Adaptive Safe Braking and Distance Prediction for Overhead Cranes With Multivariation Using MLP”。 摘要 桥式起重机的紧急制动及其制动距离预测是…

DeepSeek实战--各版本对比

1.对比 版本参数量优势劣势使用场景竞品DeepSeek-V36710亿(MoE架构,激活370亿)开源、高效推理(60 TPS)、低成本(API费用低)、中文处理能力突出(90%准确率多模态能力有限通用任务&am…

从0开始建立Github个人博客(hugoPaperMod)

从0开始建立Github个人博客(hugo&PaperMod) github提供给每个用户一个网址,用户可以建立自己的静态网站。 一、Hugo hugo是一个快速搭建网站的工具,由go语言编写。 1.安装hugo 到hugo的github标签页Tags gohugoio/hugo选择一个版本&#xff0c…

【AI论文】WebThinker:赋予大型推理模型深度研究能力

摘要:大型推理模型(LRMs),如OpenAI-o1和DeepSeek-R1,展示了令人印象深刻的长期推理能力。 然而,他们对静态内部知识的依赖限制了他们在复杂的知识密集型任务上的表现,并阻碍了他们生成需要综合各…