structuredClone vs lodash.cloneDeep:核心差异与选型指南

做前端这么多年,JSON.parse(JSON.stringify(obj)) 这行代码你一定不陌生。

它简单、好用、随处可见------但也处处是坑:

  • 函数?没了。
  • undefined?没了。
  • Symbol?没了。
  • 循环引用?直接报错。
  • Date、RegExp、Map、Set?统统变成你不认识的样子。

2022 年,浏览器终于推出了原生的深拷贝 API ------ structuredClone() 。它一度被称作"JSON 深拷贝的终结者"。

但现实是:它并不是 lodash.cloneDeep 的替代品,而是互补品。

一个处理纯数据,一个兜底带行为的数据。今天就把两者的边界讲清楚。

一、核心能力对比

根据 greatfrontend 链接1 链接2 整理的对比表:

值 / 场景 structuredClone Lodash cloneDeep
嵌套对象 / 数组 ✅ 克隆 ✅ 克隆
Date ✅ 保留 Date ✅ 保留 Date
RegExp ✅ 保留 RegExp ✅ 保留 RegExp
Map / Set ✅ 克隆 ✅ 克隆
循环引用 ✅ 支持 ✅ 支持
函数 / 方法 ❌ 抛 DataCloneError ✅ 按引用保留
Symbol 键 ❌ 不克隆 ✅ 克隆
类实例原型链 ❌ 丢失,变普通对象 ✅ 保留原型链
BigInt ✅ 保留 ✅ 保留
instanceof 检查 ❌ 类实例克隆后 instanceof 失效 ✅ 保持类实例身份

二、关键差异详解

1. 函数处理:最本质的分水岭

structuredClone 遇到函数直接抛异常:

js

scss 复制代码
structuredClone({ fn: () => {} }); 
// ❌ DataCloneError: () => {} could not be cloned.

cloneDeep 将函数按引用保留 :

js

ini 复制代码
const obj = { fn: () => console.log('hello') };
const clone = _.cloneDeep(obj);
clone.fn === obj.fn; // true(函数本身是同一引用)

这意味着:如果你的数据模型包含方法或回调函数,structuredClone 完全不可用,只能选 cloneDeep。

2. 原型链:类实例的命运不同

structuredClone 返回普通对象,原型链被剥离 :

js

javascript 复制代码
class User {
  constructor(name) { this.name = name; }
  greet() { return `Hi, ${this.name}`; }
}

const u = new User('张三');
const cloned = structuredClone(u);

cloned instanceof User; // ❌ false
cloned.greet;           // ❌ undefined

cloneDeep 保留原型链 :

js

ini 复制代码
const cloned = _.cloneDeep(u);
cloned instanceof User; // ✅ true
cloned.greet();         // ✅ 'Hi, 张三'

但注意:两者都不会重新执行构造函数 ,只在构造时生效的不变量不会在克隆对象上重新应用 。

3. Symbol 键的处理

structuredClone 不克隆 Symbol 键的属性 ,cloneDeep 则可以 。

js

ini 复制代码
const sym = Symbol('key');
const obj = { [sym]: 'value' };

structuredClone(obj); // ❌ { }
_.cloneDeep(obj);     // ✅ { [sym]: 'value' }

三、性能对比

性能数据存在一定争议,取决于测试场景和对象规模:

  • 多份来源认为 structuredClone 在大型 / 复杂对象上更快 ,因为底层是原生 C++ 实现,且与 postMessage、IndexedDB 共用同一套高效算法 。
  • 也有 benchmark 显示在特定数组拷贝场景下 cloneDeep 略快 (680K vs 590K ops/sec),但这可能受测试用例和运行环境影响。

务实结论 :性能不应作为首要选型依据。两者在大多数业务场景下都够快,差距不会成为瓶颈。功能匹配度才是决定因素。

四、选型决策树

根据 greatfrontend 的建议,按顺序判断 :

text

javascript 复制代码
1. 对象包含函数、方法,或类实例的原型链必须保留?
   → 是:使用 lodash.cloneDeep
   → 否:继续

2. 对象包含 Date、Map、Set、RegExp、TypedArray、ArrayBuffer 或循环引用?
   → 是:使用 structuredClone(原生、无依赖)
   → 否:继续

3. 所有值都是严格 JSON 安全的(字符串、有限数字、布尔、null、纯对象/数组)?
   → 是:两者均可,优先 structuredClone 作为默认

五、一句话总结

structuredClone 是现代 JavaScript 深拷贝的默认选择;只有当函数、Symbol 或类实例原型链成为硬性需求时,才需要退回 lodash.cloneDeep 。

如果你的项目是纯数据流(无函数、无类实例),structuredClone 是零依赖、更简洁、且与浏览器底层机制一致的首选。如果数据结构中嵌入了行为(方法、回调),cloneDeep 仍是当前最稳妥的兜底方案。

相关推荐
lerhxx1 小时前
AI 应用中的上下文管理 —— 从"上下文窗口"到"分层压缩"的工程实践
前端·javascript
雪芽蓝域zzs2 小时前
第 3 节:地图点击事件,点击获取经纬度
vue.js
Mahut2 小时前
我在 Mac 上做了个本地剪辑器
javascript·架构·产品
WayneX2 小时前
开源 Vue 3 组件库 Morya UI:把组件、文档、AI 工具链一起做进一个包
前端·vue.js·前端框架
汉堡大王95272 小时前
GPT-6 上线 48 小时,我扒开了 Intelligent UI 的运行机制:DIL、沙箱 Worker 和一个 React 式协调器
前端·javascript·后端
hai_android2 小时前
Chat 聊天模块功能总结
前端·javascript·vue.js
创世虚拟世界3 小时前
我做了一个 3D 虚拟世界基底,基于这个再做 3D 虚拟世界或者元宇宙,会事半功倍
javascript·人工智能·3d·gitee·虚拟现实
Highcharts.js4 小时前
用Highcharts开发动态主从图表|双图联动的时间序列图表示例
javascript·数据库·信息可视化·highcharts·图表开发·动态图表