核心思路是按需定制、避开冗余逻辑、用更轻量手段处理实际数据结构:针对纯 json-like 数据用 json.parse(json.stringify(obj));含 date/regexp 时写精简递归;固定结构用解构组合;大对象分块或懒克隆。

不用 Lodash 的 cloneDeep,核心思路是:**按需定制、避开冗余逻辑、用更轻量的手段处理实际数据结构**。Lodash 的 cloneDeep 是通用型实现,覆盖 Date、RegExp、Map、Set、TypedArray、循环引用、Symbol、不可枚举属性等全部边界情况,但多数业务场景根本用不到这么全的功能——这就带来了不必要的判断、WeakMap 查表、递归调用和类型检测开销。
明确数据结构,写专用克隆函数
绝大多数前端项目中的“深拷贝”对象其实很规整:纯 JSON-like 数据(即只含 null、undefined、number、string、boolean、array、object,不含函数、Date、正则、循环引用等)。这种情况下,最高效的方式就是直接用 JSON.parse(JSON.stringify(obj))。
- 它底层由 V8 高度优化,执行极快,尤其对中等规模数据(几千个键值对以内)比 Lodash 快 2–5 倍
- 无需引入任何依赖,零打包体积
- 注意限制:不能有
undefined、function、Symbol、Date、NaN、Infinity;也不支持循环引用
用原生递归 + 类型白名单,跳过不必要分支
如果数据里偶尔含 Date 或 RegExp,但确定没有 Map/Set/循环引用,就自己写一个精简版递归函数,只处理你真正会遇到的类型:
- 去掉 WeakMap 循环引用检测(除非你确认可能有)
- 只加
instanceof Date和instanceof RegExp分支,其余一律走默认对象/数组递归 - 用
Array.isArray()替代Object.prototype.toString.call()判断数组,更快 - 省略 Symbol 和不可枚举属性处理(99% 的业务对象不用)
对固定结构对象,用结构化浅拷贝组合
比如你总在克隆一个固定 shape 的配置对象:{ id: number, name: string, items: Array }。这时完全没必要递归遍历,直接解构 + 映射即可:
const clone = { ...obj, items: obj.items.map(item => ({ ...item })) };- 层级清晰、可读性强、无递归开销、V8 可内联优化
- 适合表单数据、API 响应 DTO、UI 状态片段等已知结构场景
大对象分块或懒克隆,避免一次性压力
当要克隆上万条记录的数组时,cloneDeep 会同步阻塞主线程。可改用:
- 分批处理:用
requestIdleCallback或setTimeout(..., 0)拆成小块递归 - 按需克隆:不真正复制全部字段,而是封装一个代理对象,只在访问时才克隆对应子树(类似虚拟化思想)
- 用结构共享:对不变部分(如公共 schema、常量字段)直接复用引用,只深拷贝变动部分
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











