讲师中心 微信公众号

工具推荐

视频效率加速
Seko
Seko

AI短剧一键生成成片

剧云
剧云

中文短剧剧本制作平台

updream

一键生成高质量推广成片

AniShort
AniShort

AI短剧协同制作平台

js 如何使用cloneDeep深度克隆对象数组

梦涛小哥_3255

梦涛小哥_3255

发布时间:2025-08-12 08:01:01

|

310人浏览过

|

来源于php中文网

原创

要深度克隆对象数组,必须使用能递归复制嵌套对象的方法;2. json.parse(json.stringify()) 虽常用,但会丢失函数、undefined、symbol、bigint,将日期转为字符串,正则变空对象,且不支持循环引用;3. lodash 的 _.clonedeep() 能处理日期、正则、map、set 等复杂类型,是更稳健的方案;4. 原生 structuredclone() api 支持日期、正则、数组、嵌套对象甚至循环引用,但不兼容老版本浏览器,是未来推荐的轻量选择;5. 自行实现递归克隆函数可行但复杂,需处理类型判断和循环引用,一般不建议。深度克隆的本质是切断引用关系,确保新旧对象完全独立,避免修改副本影响原始数据,这在状态管理等场景中至关重要。

js 如何使用cloneDeep深度克隆对象数组

在 JavaScript 里要深度克隆一个对象数组,可不是简单地用

...
展开运算符或者
slice()
就能搞定的。那些方法只能做“浅克隆”,意思是数组里的基本类型值被复制了,但如果数组元素是对象,复制的只是它们的引用。要真正做到“深度”,让每个嵌套的对象也独立出来,你需要更强力的手段,比如利用 JSON 的序列化和反序列化,或者引入像 Lodash 这样的工具库,再或者,自己写一个递归函数来精细控制。

说实话,在 JavaScript 里处理深度克隆,尤其是一个包含复杂对象的数组,最常见也最“偷懒”的方法就是

JSON.parse(JSON.stringify(originalArray))
。这招简单粗暴,但有效,它把你的数组先变成一个 JSON 字符串,再解析回来,过程中就切断了所有原始引用。不过,这招有明显的局限性,比如它会丢失函数、
undefined
、
Symbol
、
BigInt
,日期对象会变成字符串,正则表达式会变成空对象等等。所以,如果你的数据结构比较纯粹,都是可序列化的基本类型和普通对象,那它够用。

如果你追求更稳健、更全面的解决方案,Lodash 库提供的

_.cloneDeep()
方法几乎是行业标准。它能处理各种复杂的数据类型,包括日期、正则表达式、Map、Set,甚至循环引用(虽然处理循环引用时它有自己的策略)。在大型项目里,引入 Lodash 的这个方法,能省去你不少麻烦,而且代码可读性也很好。

// 使用 Lodash 的 _.cloneDeep
import _ from 'lodash';

const originalArray = [
  { id: 1, name: 'Item A', details: { value: 10, tags: ['new', 'hot'] }, createdAt: new Date() },
  { id: 2, name: 'Item B', details: { value: 20, tags: ['old'] }, func: () => console.log('hi') }
];

const clonedArray = _.cloneDeep(originalArray);

// 验证深度克隆
clonedArray[0].details.value = 100;
clonedArray[1].name = 'Item C';
clonedArray[0].createdAt.setFullYear(2000); // 修改克隆后的日期

console.log('Original Item A Value:', originalArray[0].details.value); // 应该还是 10
console.log('Cloned Item A Value:', clonedArray[0].details.value);     // 应该是 100
console.log('Original Item B Name:', originalArray[1].name);         // 应该还是 'Item B'
console.log('Cloned Item B Name:', clonedArray[1].name);             // 应该是 'Item C'
console.log('Original Item A Date Year:', originalArray[0].createdAt.getFullYear()); // 应该还是当前年份
console.log('Cloned Item A Date Year:', clonedArray[0].createdAt.getFullYear());     // 应该是 2000
console.log('Original Item B Func:', originalArray[1].func); // Lodash会丢失函数,这里会是 undefined

对于那些对性能有极致要求,或者数据结构极其特殊,且不想引入第三方库的场景,你也可以考虑自己实现一个递归的深度克隆函数。但这通常比较复杂,需要处理各种边缘情况,比如循环引用,不同类型的对象(数组、日期、正则、Map、Set等),以及原型链的继承问题。一般情况下,不建议自己造这个轮子。

为什么简单的赋值或展开运算符不能实现深度克隆?

这其实是 JavaScript 中一个非常基础但也容易让人迷惑的概念:值类型和引用类型。当你用

const newArr = oldArr;
或者
const newArr = [...oldArr];
这样的方式去“复制”一个数组时,如果数组里面存放的是基本数据类型(比如数字、字符串、布尔值),那它们确实会被复制一份。但一旦数组里有对象(包括普通对象、数组、函数等),你复制的就不是对象本身,而是指向这些对象的“引用”或者说“地址”。这就像你复制了一本书的目录,而不是书的全部内容。

所以,当你修改

newArr[0].name
时,因为
newArr[0]
和
oldArr[0]
指向的是内存中的同一个对象,你实际上修改的是同一个对象,结果就是
oldArr[0].name
也会跟着变。这在实际开发中一不小心就可能导致意想不到的副作用,尤其是在处理组件状态、数据不可变性这些场景时,简直是“灾难现场”。你本以为自己操作的是一份独立的数据,结果却影响了原始数据,这可不是闹着玩的。理解这一点,是掌握 JavaScript 数据操作的关键一步。

使用 JSON.parse(JSON.stringify()) 进行深度克隆有哪些坑?

JSON.parse(JSON.stringify())
这种方式虽然简单,但它的“坑”可不少,尤其是在你处理复杂数据时。它的核心原理是利用 JSON 规范来序列化和反序列化数据,而 JSON 规范对数据类型有着严格的限制。

CDP浏览器大师
CDP浏览器大师

CDP浏览器大师:通过Chrome DevTools Protocol驱动已登录浏览器实现自动化任务,解决反爬封号、选择器失效、SPA路由难导航、固定sleep不准四大痛点。核心能力包括UA伪装、WebGL/Canvas指纹混淆、智能等待、动态选择器以及可视化调试。

下载

首先,它会丢失函数。对象里的方法或者任何函数属性都会在序列化过程中被直接忽略。因为 JSON 压根就不支持存储函数。

const objWithFunc = {
  name: 'Test',
  greet: function() { console.log('Hello'); }
};
const cloned = JSON.parse(JSON.stringify(objWithFunc));
console.log(cloned.greet); // undefined

其次,

undefined
、
Symbol
、
BigInt
也会被忽略
。它们在 JSON 字符串中无法表示,所以会被直接“抹掉”。

const objWithSpecial = {
  a: undefined,
  b: Symbol('sym'),
  c: 10n // BigInt
};
const cloned = JSON.parse(JSON.stringify(objWithSpecial));
console.log(cloned); // {} - 什么都没了

再来,

Date
对象会变成字符串。日期对象会被转换成 ISO 8601 格式的字符串,而不是一个
Date
对象实例。如果你需要对日期进行操作,还得手动转换回来。

const objWithDate = {
  eventDate: new Date()
};
const cloned = JSON.parse(JSON.stringify(objWithDate));
console.log(cloned.eventDate);       // "2023-10-27T08:30:00.000Z" (一个字符串)
console.log(cloned.eventDate instanceof Date); // false

还有,

RegExp
对象会变成空对象。正则表达式对象也会在序列化后变成一个普通的空对象
{}
。

const objWithRegExp = {
  pattern: /abc/g
};
const cloned = JSON.parse(JSON.stringify(objWithRegExp));
console.log(cloned.pattern); // {}

最后,它不能处理循环引用。如果你的对象结构中存在循环引用(比如 A 引用 B,B 又引用 A),

JSON.stringify()
会直接抛出一个
TypeError: Converting circular structure to JSON
错误。这是它最大的局限性之一。

所以,虽然

JSON.parse(JSON.stringify())
用起来方便,但你得清楚它的适用场景和这些潜在的“陷阱”。一旦数据里包含上述任何一种类型,你就得考虑其他更健壮的方案了。

除了 Lodash,还有哪些库或方法可以实现更健壮的深度克隆?

Lodash 的

_.cloneDeep
确实是多数开发者的首选,但 JavaScript 生态系统一直在进化,我们也有了更多原生的或者其他库的选择。

一个非常值得关注的,是现代浏览器和 Node.js(v17+)提供的原生 API:

structuredClone()
。这个方法原本是用于 Web Workers 之间传递消息的,现在被暴露出来,可以直接用于深度克隆。它的强大之处在于,它能够处理许多
JSON.parse(JSON.stringify())
无法处理的数据类型,包括
Date
、`

热门AI工具

更多
Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2355

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

3882

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

1296

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

4499

2025.09.10

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

5036

2023.06.20

正则表达式不包含
正则表达式不包含

正则表达式,又称规则表达式,,是一种文本模式,包括普通字符和特殊字符,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式的文本。php中文网给大家带来了有关正则表达式的相关教程以及文章,希望对大家能有所帮助。

3481

2023.07.05

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

9742

2023.07.05

java正则表达式匹配字符串
java正则表达式匹配字符串

在Java中,我们可以使用正则表达式来匹配字符串。本专题为大家带来java正则表达式匹配字符串的相关内容,帮助大家解决问题。

832

2023.08.11

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

100

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MDN CSS 文档与布局指南
MDN CSS 文档与布局指南

共0课时 | 0人学习

Postman安装指南
Postman安装指南

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn