structuredclone()是现代环境首选方案,支持date、map、set等内置类型并自动处理循环引用;旧环境可用json.parse(json.stringify())(仅限纯数据)、手写递归克隆或lodash.clonedeep。

处理包含多种内置类型的对象克隆,关键在于选择能覆盖目标类型、不丢失结构且安全应对循环引用的方案。现代环境优先用 structuredClone();旧环境或特殊需求则需组合判断与递归重建。
structuredClone():现代首选,开箱即用
它原生支持 Date、Map、Set、RegExp、ArrayBuffer、TypedArray、Error(部分环境)甚至 DOM 节点,自动识别并保留原型链(对可结构化对象),同时内置循环引用检测,无需额外逻辑。
- ✅ 一行搞定:
const clone = structuredClone(original) - ✅ 兼容性:Chrome 98+、Firefox 94+、Edge 98+、Node.js 18.12+ 默认支持
- ❌ 不支持:函数、Symbol、undefined、BigInt(会忽略或报错)
JSON.parse(JSON.stringify()):仅限纯数据,慎用
适合只有字符串、数字、布尔值、null、数组、普通对象的场景。一旦含 Date、RegExp、Map、Set 或函数,就会出错或失真。
- ⚠️ Date 变成字符串,
new Date().toISOString()格式不可逆 - ⚠️ RegExp 变成空对象
{},正则逻辑完全丢失 - ⚠️ Map/Set 被丢弃,循环引用直接抛
TypeError
手写递归克隆:完全可控,适配定制逻辑
当需要跳过特定字段、转换类型、或兼容不支持 structuredClone 的运行时,可手动实现。核心是区分类型、缓存已处理对象(防循环)、逐类重建。
- Date →
new Date(obj.getTime()) - RegExp →
new RegExp(obj.source, obj.flags) - Map →
new Map([...obj].map(([k, v]) => [k, deepClone(v)])) - Set →
new Set([...obj].map(v => deepClone(v))) - 用
WeakMap缓存源对象与克隆体映射,避免重复处理和栈溢出
第三方库(如 lodash.cloneDeep):生产环境稳妥之选
经过大量边界测试,支持几乎所有常见类型(包括稀疏数组、不可枚举属性、自定义构造器),并提供 customizer 钩子控制特定字段行为。
- ✅ 稳健处理循环引用、嵌套 Symbol(可选)、Error 实例
- ✅ 若项目已引入 lodash,按需导入
cloneDeep即可,体积可控 - ⚠️ 函数默认保留引用(JS 无法真正复制函数体),需明确预期











