structuredclone()是现代环境首选深拷贝方案,支持map/set/date等类型及循环引用,但需检查兼容性并捕获datacloneerror;旧环境可降级用json或lodash.clonedeep。

用 structuredClone() 是目前最接近“完美”的方案,前提是运行环境支持且数据结构合规。它能保留 Map/Set 的类型、正确处理嵌套与循环引用,而 JSON 方案会丢类型、手写易出错。
优先用 structuredClone() —— 现代环境的首选
只要目标环境是 Chrome 98+、Firefox 94+、Safari 15.4+ 或 Node.js 17.0+,就应直接使用:
- 它原生支持 Map、Set、Date、RegExp、ArrayBuffer、BigInt 和循环引用
- 克隆后仍是
Map实例,cloned instanceof Map返回 true - 键和值都被深拷贝:比如 Set 作为 Map 的 key,克隆后仍是独立副本,原 Set 不再能命中
- 必须加运行时检查和错误捕获,因为遇到函数、undefined、Symbol、Promise 会抛
DataCloneError
示例:
if (typeof structuredClone === 'function') {
try {
const cloned = structuredClone(originalMapOrObj);
} catch (err) {
if (err.name === 'DataCloneError') {
console.error('不支持的类型,如 function 或 undefined');
}
}
} else {
// 降级处理
}
避开 structuredClone 的限制场景
以下情况它无法工作,需提前识别或转换:
- Map 的键含函数 / undefined / Symbol:直接报错,不可恢复
- WeakMap / WeakSet:无法序列化,调用即抛错
- 带 getter/setter 或不可枚举属性的对象:只拷贝可枚举自有属性,访问器丢失
- Error 对象、Promise、DOM 节点:多数环境不支持,行为不一致
若原始数据可控,建议预处理:移除非法键、将 WeakMap 换成 Map、把函数转为配置描述等。
兼容旧环境的务实替代方案
当需支持 IE、旧 Edge 或某些 Node.js 版本时,不能依赖 structuredClone,但也不必全量手写:
-
纯数据 + 无循环:仍可用
JSON.parse(JSON.stringify(obj)),但务必确认不含 Date/Map/Set/undefined - 含 Map/Set 但结构已知:单独封装克隆函数,例如:
function cloneMap(map) {
const result = new Map();
for (const [key, value] of map) {
result.set(
typeof key === 'object' && key !== null ? structuredClone?.(key) ?? JSON.parse(JSON.stringify(key)) : key,
typeof value === 'object' && value !== null ? structuredClone?.(value) ?? JSON.parse(JSON.stringify(value)) : value
);
}
return result;
}
-
复杂通用场景:引入
lodash.clonedeep,它覆盖类型广(包括 Map/Set),但注意它不克隆原型链上的方法,也不处理 WeakMap
关键提醒:Map/Set 的 set/get 本身不深拷贝
很多人误以为往 Map 里 set(obj) 就自动隔离了数据——其实只是存了引用。后续修改 obj,Map 里取出来的也会变。
- 真正解耦,必须在
set前手动克隆:map.set(key, structuredClone(value)) - 如果 value 是简单对象且确定无 Date/Map/循环,也可用
JSON.parse(JSON.stringify(value)) - 避免在循环中反复调用克隆,性能敏感时建议缓存或设计不可变结构
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











