首选 structuredClone:安全省心,支持 Date、RegExp、Map、Set 等及循环引用,但不支持函数、undefined、Symbol 键;旧环境用 WeakMap 缓存递归方案;JSON 方式仅限纯数据;Lodash cloneDeep 全面但增体积。

要安全地深度克隆包含特殊对象(如 Date、RegExp、Map、Set、ArrayBuffer 等)的复杂结构,不能依赖简单方法,必须兼顾类型识别、循环引用防护和原型链保留。现代环境优先用原生 structuredClone;旧环境或需精细控制时,应采用带 WeakMap 缓存的递归方案。
首选 modern 方案:structuredClone
这是目前最安全、最省心的原生方法,自动支持:
-
Date、RegExp、Error、Blob、File、ImageData -
Map、Set、ArrayBuffer及其视图(TypedArray、DataView) - 循环引用 —— 内置处理,无需额外逻辑
- 完整嵌套结构,无论多深
注意限制:不支持函数、undefined、Symbol 键、WeakMap/WeakSet。若数据中含这些,需提前过滤或降级处理。
兼容性:Chrome 98+、Firefox 94+、Safari 15.4+、Node.js 17.0+。生产前建议检测:
立即学习“Java免费学习笔记(深入)”;
if (typeof structuredClone === 'function') { ... }兼容旧环境:自定义递归 deepClone
当需支持 IE 或老版 Node.js,或需要定制行为(如保留 Symbol 属性、处理自定义类),推荐手写递归函数,并严格包含以下三要素:
-
类型精准判断:用
Object.prototype.toString.call(obj)或obj instanceof X区分Date、RegExp、Map、Set、Array、普通Object -
循环引用防护:用
WeakMap缓存已克隆对象,遇到重复引用直接返回缓存值 -
属性全覆盖复制:用
Reflect.ownKeys()获取所有键(含不可枚举属性和 Symbol),再逐个递归克隆
关键示例逻辑片段:
if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
if (obj instanceof Map) { const map = new Map(); obj.forEach((v, k) => map.set(deepClone(k), deepClone(v))); return map; }
if (obj instanceof Set) { const set = new Set(); obj.forEach(v => set.add(deepClone(v))); return set; }
慎用但可应急:JSON.parse(JSON.stringify())
仅适用于纯数据对象(无函数、无日期、无正则、无 undefined、无循环引用、无 Symbol)。它会静默丢失:
-
Date→ 字符串(如"2026-09-03T11:25:00.000Z") -
undefined、function、Symbol键 → 被忽略 -
Map/Set→ 变成空对象{} - 循环引用 → 直接抛错
TypeError: Converting circular structure to JSON
适合配置项、API 响应体等已知结构干净的场景,不建议用于通用克隆逻辑。
高要求工程场景:Lodash cloneDeep
若项目已引入 Lodash,_.cloneDeep 是经过大量实战验证的成熟方案:
- 支持全部 JS 类型(包括函数、Symbol、自定义类实例)
- 自动处理循环引用
- 可配置 customizer 函数,干预特定类型克隆行为
- 性能优化良好,有完善的测试覆盖
代价是增加约 20KB(gzip 后)的包体积。如对 bundle size 敏感,建议按需引入:import { cloneDeep } from 'lodash-es'。


















