彻底搞懂JavaScript深拷贝与浅拷贝:从原理到实战避坑

在JavaScript日常开发中,数据拷贝是绕不开的操作,但很多人都踩过“改新对象、原对象跟着变”的坑,排查半天发现根源是没分清浅拷贝和深拷贝。这篇文章从底层存储机制讲起,结合实际业务场景和可直接复用的代码案例,把深浅拷贝的核心逻辑、实现方式和边界情况讲透,帮大家在开发中精准选型、避免踩雷。

一、前置核心:JS数据类型的存储逻辑

想分清深浅拷贝,必须先吃透JS数据类型的存储规则——这是所有拷贝行为的底层逻辑,没搞懂这个,后面的内容都是空中楼阁。

1. 数据类型分类及存储差异

JS数据分两大类,存储位置和拷贝特性完全不同,直接决定了拷贝后的表现:

类型分类

包含具体类型

存储位置

核心拷贝特点

基本数据类型

Number、String、Boolean、Null、Undefined、Symbol、BigInt

栈内存(Stack)

拷贝时直接复制「值」,新老数据相互独立,修改互不影响

引用数据类型

Object(数组、普通对象、函数、Date、RegExp等)

栈存引用地址,堆存实际值(Heap)

默认拷贝「引用地址」,新老对象共享同一块堆内存数据

2. 直观对比:基本类型与引用类型拷贝差异

基本类型拷贝:本质是值拷贝,天然具备“深拷贝”的效果,修改新变量不会牵连原变量。

// 基本类型拷贝示例 let num1 = 100; let num2 = num1; // 直接复制num1的值 num2 = 200; // 修改新变量 console.log(num1); // 100(原数据不受影响) console.log(num2); // 200(新数据独立)

引用类型默认拷贝:只复制引用地址,新老对象指向同一块堆内存,改一个就会影响另一个,这就是浅拷贝的核心问题。

// 引用类型默认浅拷贝 let obj1 = { name: "张三", age: 22 }; let obj2 = obj1; // 复制的是引用地址,而非实际数据 obj2.name = "李四"; // 修改新对象属性 console.log(obj1.name); // 李四(原对象被同步修改) console.log(obj2.name); // 李四

关键结论:浅拷贝和深拷贝的差异,仅存在于引用数据类型中。基本类型的拷贝都是“值拷贝”,不存在深浅之分。

二、浅拷贝:只做一层的“表面功夫”

1. 浅拷贝的核心特性

浅拷贝针对引用数据类型,仅复制对象表层结构——也就是栈内存引用地址对应的第一层数据。如果对象存在多层嵌套(比如对象里套对象、数组里套对象),内层的引用类型依然共享堆内存,修改内层数据会同步影响原对象。

2. 常用浅拷贝实现方式(附实战案例)

(1)数组浅拷贝

数组的slice()、concat()方法,以及ES6扩展运算符,都是常用的浅拷贝方式,用法简单但要注意内层数据共享的问题。

const arr1 = [1, 2, { score: 90 }]; // 三种常用浅拷贝方式 const arr2 = [...arr1]; // 扩展运算符(最简洁) const arr3 = arr1.slice(); // slice方法,不传参复制全量 const arr4 = arr1.concat(); // concat方法,空参数拼接 // 修改内层嵌套对象 arr2[2].score = 100; // 所有浅拷贝数组的内层数据都会同步变化 console.log(arr1[2].score); // 100(原数组受影响) console.log(arr3[2].score); // 100 console.log(arr4[2].score); // 100
(2)对象浅拷贝

Object.assign()和ES6扩展运算符,是对象浅拷贝的主流方式,适合单层对象的复用场景。

const obj1 = { a: 1, b: { c: 2 } }; // 两种对象浅拷贝方式 const obj2 = Object.assign({}, obj1); // Object.assign const obj3 = { ...obj1 }; // 扩展运算符(更直观) // 修改内层嵌套对象 obj2.b.c = 3; // 原对象和其他浅拷贝对象的内层数据同步变化 console.log(obj1.b.c); // 3(原对象受影响) console.log(obj3.b.c); // 3

3. 浅拷贝的适用场景

浅拷贝性能开销小、实现简单,不用做递归处理,适合以下场景:

  • 对象/数组为单层结构,无任何嵌套的引用类型;

  • 仅复用表层数据,且内层数据为只读状态,不涉及修改操作。

三、深拷贝:完全独立的“全量复制”

1. 深拷贝的核心特性

深拷贝会递归遍历引用数据类型的所有层级,把每一层的实际数据都复制到新的堆内存中,最终生成一个和原对象完全独立的新对象。无论修改新对象的哪一层数据,都不会对原对象产生任何影响。

2. 三种深拷贝实现方式(从简单到生产可用)

(1)简易版:JSON.parse(JSON.stringify())

这是日常开发中最常用的快速深拷贝方案,不用依赖任何库,一行代码就能实现,适合简单场景。

const obj1 = { name: "张三", info: { age: 22, hobby: ["篮球", "游戏"] } }; // 一行代码实现深拷贝 const obj2 = JSON.parse(JSON.stringify(obj1)); // 修改新对象的内层数据 obj2.info.age = 25; obj2.info.hobby[0] = "足球"; // 原对象数据不受影响 console.log(obj1.info.age); // 22 console.log(obj1.info.hobby[0]); // 篮球

注意局限性:这种方式有明显短板,生产环境需谨慎使用,不支持以下场景:

  • 无法拷贝函数、Undefined、Symbol(会被直接忽略);

  • 无法处理循环引用对象(会直接报错,导致程序中断);

  • 特殊对象拷贝失真(Date转为字符串、RegExp转为空对象)。

我们用一个案例直观感受这些问题:

const obj = { fn: () => console.log('test'), // 函数类型 time: new Date(), // Date类型 undef: undefined, // Undefined类型 sym: Symbol('foo') // Symbol类型 }; const copyObj = JSON.parse(JSON.stringify(obj)); console.log(copyObj.fn); // undefined(函数被忽略) console.log(copyObj.time); // 字符串(Date失真) console.log(copyObj.undef); // 不存在(Undefined被忽略) console.log(copyObj.sym); // 不存在(Symbol被忽略)
(2)进阶版:手动实现递归深拷贝(兼容特殊场景)

手动实现深拷贝能帮我们吃透底层逻辑,还能自定义处理特殊类型。下面是优化后的完整实现,兼容Date、RegExp和循环引用,可直接用于中小型项目。

/** * 优化版递归深拷贝(兼容Date、RegExp、循环引用) * @param {*} target 要拷贝的目标数据 * @param {WeakMap} map 缓存已拷贝对象,解决循环引用 * @returns 拷贝后的新数据 */ function deepClone(target, map = new WeakMap()) { // 1. 处理基本类型和null(直接返回值,无需拷贝) if (typeof target !== 'object' || target === null) { return target; } // 2. 处理循环引用:已拷贝过则直接返回缓存对象,避免死循环 if (map.has(target)) { return map.get(target); } // 3. 处理Date类型:创建新Date对象,保留原时间 if (target instanceof Date) { const newDate = new Date(target.getTime()); map.set(target, newDate); return newDate; } // 4. 处理RegExp类型:保留原正则表达式的源和修饰符 if (target instanceof RegExp) { const newReg = new RegExp(target.source, target.flags); map.set(target, newReg); return newReg; } // 5. 处理数组:创建新数组,递归拷贝每一项 if (target instanceof Array) { const newArr = []; map.set(target, newArr); target.forEach(item => newArr.push(deepClone(item, map))); return newArr; } // 6. 处理普通对象:创建新对象,遍历自身属性递归拷贝 if (target instanceof Object) { const newObj = {}; map.set(target, newObj); // 只拷贝自身可枚举属性,避免拷贝原型链上的属性 for (const key in target) { if (target.hasOwnProperty(key)) { newObj[key] = deepClone(target[key], map); } } return newObj; } } // 测试:包含循环引用和特殊类型 const obj1 = { a: 1, date: new Date(), reg: /test/g, arr: [1, { b: 2 }] }; // 制造循环引用(obj1指向自身) obj1.self = obj1; const obj2 = deepClone(obj1); // 验证拷贝效果 console.log(obj2.date instanceof Date); // true(Date类型正常) console.log(obj2.reg instanceof RegExp); // true(RegExp类型正常) console.log(obj2.self === obj2); // true(循环引用处理正常) // 修改新对象内层数据,验证独立性 obj2.arr[1].b = 100; console.log(obj1.arr[1].b); // 2(原数据无变化)

这个实现的核心优化点:用WeakMap缓存已拷贝对象,解决循环引用导致的递归死循环;针对性处理Date和RegExp类型,避免拷贝失真,基本能覆盖大部分业务场景。

(3)生产版:第三方库lodash.cloneDeep()

生产环境中,不建议自己造轮子——成熟的第三方库已经处理了所有边界情况(包括函数、循环引用、特殊对象等),稳定性和兼容性更有保障。最常用的就是lodash的cloneDeep()方法。

// 1. 安装lodash(npm/yarn) // npm install lodash --save // yarn add lodash // 2. 引入并使用(可按需引入,减少体积) const _ = require('lodash'); // 按需引入方式:const cloneDeep = require('lodash/cloneDeep'); const obj1 = { name: "李四", fn: () => console.log("hello deep clone"), // 函数类型 date: new Date(), // Date类型 reg: /test/g, // RegExp类型 info: { age: 24 } }; const obj2 = _.cloneDeep(obj1); // 修改新对象内层数据 obj2.info.age = 26; // 验证效果:原对象无变化,特殊类型拷贝正常 console.log(obj1.info.age); // 24 console.log(obj2.fn()); // hello deep clone(函数正常) console.log(obj2.date instanceof Date); // true(Date正常)

四、实战选型指南:深浅拷贝怎么选?

开发中不用盲目追求深拷贝,结合业务场景选型才是最优解,既保证功能又兼顾性能。整理了常见场景的选型建议:

业务场景

推荐拷贝方式

选择理由

单层对象/数组,无嵌套引用类型

浅拷贝(扩展运算符/Object.assign)

性能最优,实现简单,无多余递归开销

多层嵌套引用类型,需完全独立数据

深拷贝

避免修改新数据影响原对象,保证数据安全性

数据含函数、循环引用、特殊对象

lodash.cloneDeep()

JSON方式无法处理,手动实现成本高,库更稳定

简单演示、临时数据处理(无特殊类型)

JSON.parse(JSON.stringify())

一行代码搞定,无需依赖第三方库,高效便捷

五、总结与实战技巧

其实深浅拷贝的核心很简单:浅拷贝抄“地址”,深拷贝抄“全量数据”。记住以下几点,就能在开发中灵活应对:

  1. 基本类型拷贝都是值拷贝,深浅拷贝仅针对引用类型;

  2. 浅拷贝适合单层结构,深拷贝适合多层嵌套结构,避免过度使用深拷贝(性能开销更大);

  3. 生产环境优先用lodash.cloneDeep(),简易场景用JSON方法,学习/面试场景可手动实现递归拷贝;

  4. 快速验证是否为深拷贝:用“===”判断新老对象,若结果为false,且内层属性修改互不影响,即为深拷贝。

深浅拷贝是JS基础中的重点,也是面试高频考点,吃透底层原理和选型逻辑,不仅能避免开发踩坑,还能应对面试中的延伸问题。文中所有代码都已实测可用,大家可以直接复制到项目中复用。

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

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

相关文章

黑客神器Kali还不会安装?手把手教你从下载、安装到使用_kali linux 使用

一 、下载kali Linux镜像 https://www.kali.org/get-kali/#kali-installer-images 二、开始安装 kali linux 基于Debian linux ,所以选择的时候安装你下载的iso镜像来选择 32位或者64位。 1、选择图形化安装 2、中文简体, continue继续----中国—汉语…

端云协同评测 JSON Schema + Failure Taxonomy

一、设计原则 这套 Schema 的目标是: 评的是系统行为,不是模型输出 能复现、能回放、能自动打分 Failure 是一等公民(不是附属) 端 / 云 / Agent 责任可归因 二、顶层结构总览 {"scenario_meta": {...},"ini…

多商户多仓库带扫描云进销存系统ERP管理系统Saas营销版无限商户源码

多商户多仓库带扫描云进销存系统ERP管理系统Saas营销版无限商户源码 "当你的仓库管理员拿着扫描枪骂娘的时候,就知道传统的ERP系统该升级了。咱们今天要聊的这个多商户多仓库系统,用Go语言重构的库存核销接口能把响应速度压到15ms以内——别急着质…

多 Agent / 多策略 A/B 评测系统

多 Agent / 多策略 A/B 评测 在相同场景分布下, 对不同 Agent 结构 / 决策策略 / 阈值 / Prompt, 进行可复现、可归因、可统计的行为级对比评测。关键词只有三个: 同场景 行为级 可归因一、为什么 Agent 一定要做 A/B,而不是“…

网络安全工程师必考的几大证书!

目前网络安全行业,国内都有哪些证书可以考。 一、CISP-PTE (国家注册渗透测试工程师) CISP-PTE即注册信息安全渗透测试工程师,该证书由中国信息安全测评中心颁发,证书是国内唯一认可的渗透测试认证,专业性…

【Vibe Coding百图计划】别卷了,来写个会跳的心放松一下~

文章目录写在前面系列文章项目架构技术需求主要代码代码分析写在后面写在前面 用代码写一封深情告白信——这是我为心爱之人准备的一份特别礼物。当程序运行时,一个跳动的粉色爱心在黑暗中缓缓浮现,伴随着“I Love You!”的温柔告白,整个画面…

Failure taxonomy + JSON 场景自动生成器

Agent 评测体系自动化引擎层 ✅ Failure Taxonomy(可判因、可统计、可演化) ✅ JSON 场景自动生成器(可规模化、可控分布) ✅ Failure → 场景 → 评测 的闭环设计 一、总体目标 我们要解决的问题是: 如何系统性地产生…

Agent Policy 自动搜索(Failure-as-Reward)

如何在端云协同 Agent 里自动学策略目标 不是让 Agent 更聪明,而是让系统“更少出事”Agent Policy 自动搜索 把 Failure taxonomy 映射为 reward / penalty, 在固定场景分布下, 自动搜索“失败最少、代价最小”的 Agent 决策策略。核心思想…

自学网络安全前先看看这三个阶段你能不能接受(含路线图)

一、为什么选择网络安全? 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地,网络安全行业地位、薪资随之水涨船高。 未来3-5年,是安全行业的黄金发展期,提前踏入…

网络安全从业8年,选专业必看,5点了解行业现状和避坑指南(非常详细,附工具包以及学习资源包)

网络安全从业8年,选专业必看,5 点了解行业现状和避坑指南 序 正值高考季,本文谨以从业者的视角,为已经计划和考虑进入安全行业的读者提供几点浅薄的行业感悟。宏观的专业选择请选择专业的咨询机构。个人意见仅供参考。 目录 信…

2026最新小学托管学校top5评测!服务深度覆盖锦江区、青羊区、双流区等地,辐射成都本地,优质培训机构权威榜单发布

随着家长对儿童成长关键期教育重视程度的提升,小学托管服务已从单纯看护升级为包含科学衔接、习惯养成、思维训练等多维度能力培养的综合教育体系。本榜单基于课程专业性、师资团队、校区环境、家校共育成效四大核心维…

端侧模型是什么意思?

端侧模型(On-device / Edge Model),指的是不依赖云端服务器、直接在“终端设备本地”运行的机器学习 / 深度学习模型。 端侧模型 模型跑在你的设备上,而不是跑在云服务器上。 比如: 手机 智能手表 摄像头 车载系统…

黑客挖漏洞是什么意思?普通人想挖到漏洞该怎么做?需要注意哪些问题?

文章目录 一.为何挖不到漏洞? 1.什么是src? (1)漏洞报告平台(2)xSRC模式 2.法律常识,挖洞前要注意不违法。 二. 漏洞挖掘的几个关键技术 1.JS在漏洞挖掘重要地位 (1)JS是什么&#…

2026飞鲨漂移艇优质供应商排名,哪家售后服务好?

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家标杆企业,为景区、文旅项目及水上娱乐投资者选型提供客观依据,助力精准匹配适配的飞鲨漂移艇品牌厂家与优质供应商。 TOP1 推荐:青岛雷旺达船舶科技有限公司…

Windows Server 与 Windows 10/11 官方安装系列号

Windows Server 2025 标准 TVRH6-WHNXV-R9WG3-9XRFY-MY832Windows Server 2025 数据中心 D764K-2NDRG-47T6Q-P8T8W-YP6DFWindows Server 2025 Datacenter:Azure Edition XGN3F-F394H-FD2MY-PP6FD-8MCRCWindows Server…

讲讲微通风系统窗推荐品牌,阜积铝业性价比如何?

随着城市住宅向高层化、临街化发展,开窗通风怕噪音灰尘,关窗密闭又闷成了很多家庭的生活痛点。微通风系统窗作为解决这一矛盾的核心产品,逐渐成为装修市场的香饽饽。但面对市面上琳琅满目的品牌,消费者往往不知如何…

你以为 PPO 很高级,其实它更像个“微调旋钮”

为什么 PPO 在真实业务里越来越重要 如果你是从论文或者课程里接触 PPO 的,那大概率会有一种“这东西看起来很厉害”的感觉。策略梯度、clip、KL 约束、reward model,一整套体系下来,很容易让人产生错觉:只要把 PP…

6 个月网络安全学习路线(零基础适用,附工具包以及学习资源包)

一、第 1-1.5 个月:基础筑基阶段(搭建安全认知框架) 核心目标:掌握计算机底层逻辑,扫清技术盲区 操作系统:深耕 Kali Linux 核心命令(权限管理、进程控制、日志分析),熟…

盘点山东客船生产厂,青岛雷旺达船舶科技公司十大厂家排得上吗

随着水上旅游市场的升温,景区、文旅集团对客船的需求日益增长,但如何选择靠谱的客船推荐厂商、客船生产厂,却成了很多采购方的难题。本文整理了关于客船推荐厂商、客船生产厂、值得推荐的客船供应商的高频问题,结合…

2026年上海婚恋陪跑机构排名,首缘婚介实力凸显值得关注

在快节奏的现代生活中,婚恋已不再是简单的相遇,而是需要专业规划与全程支持的情感旅程。无论是追求高品质婚恋体验的精英人群,还是渴望晚年幸福的银发长者,都面临着匹配难、信任难、相守难的三重困境。而婚恋陪跑服…