优先用 structuredClone(现代环境),其次手写 WeakMap 递归(兼容函数/循环引用),或用 lodash.cloneDeep(生产推荐);JSON.parse(JSON.stringify()) 会丢弃 undefined、函数、Symbol 等。

直接用 JSON.parse(JSON.stringify(obj)) 行不通——它会静默丢弃 undefined、函数、Symbol,还会把 Date 变字符串、RegExp 变空对象、Map/Set 直接消失。
用 structuredClone(推荐优先尝试)
现代浏览器和 Node.js(v17.0+)已原生支持 structuredClone(),能保留 Symbol、undefined、Date、RegExp、Map、Set、ArrayBuffer 等,但仍不支持函数和循环引用。
- 支持
undefined和Symbol键/值(只要不是作为对象的 key 时被忽略——注意:structuredClone会保留 Symbol 值,但 Symbol 作为对象属性 key 时,该 key 不会被克隆,这是规范行为) - 不拷贝函数,遇到函数会抛错:
DataCloneError - 不处理循环引用,也会报错
示例:
const obj = {
a: 1,
b: undefined,
c: () => {},
[Symbol('x')]: 'sym',
d: new Date(),
e: /test/g
};
// ✅ 能拷贝 a、b、d、e、Symbol 值(但 Symbol 键不保留)
// ❌ 遇到 c 函数会 throw Error
手写递归 + WeakMap(处理循环引用)
要真正兼容函数、Symbol、undefined、特殊对象且防循环引用,需手动实现。核心是:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 用
WeakMap缓存已克隆的对象,检测并复用,避免无限递归 - 逐类型判断:
null、基本类型、Array、Date、RegExp、Map、Set、Object - 对
Object使用Object.getOwnPropertyDescriptors()+Object.defineProperties(),可保留Symbol属性、访问器、不可枚举属性、函数等 - 函数默认直接返回原引用(深拷贝函数无通用语义,通常不复制;若需“绑定新上下文”,可用
fn.bind({}))
关键代码片段:
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
// 处理 Date、RegExp、Map、Set、Array 等
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Map) {
const mapCopy = new Map();
hash.set(obj, mapCopy);
obj.forEach((val, key) => mapCopy.set(deepClone(key, hash), deepClone(val, hash)));
return mapCopy;
}
if (obj instanceof Set) {
const setCopy = new Set();
hash.set(obj, setCopy);
obj.forEach(val => setCopy.add(deepClone(val, hash)));
return setCopy;
}
if (Array.isArray(obj)) {
const arrCopy = [];
hash.set(obj, arrCopy);
obj.forEach((item, i) => arrCopy[i] = deepClone(item, hash));
return arrCopy;
}
// 普通对象:保留 Symbol、不可枚举、getter/setter
const descriptors = Object.getOwnPropertyDescriptors(obj);
const cloned = Object.create(Object.getPrototypeOf(obj));
hash.set(obj, cloned);
for (let key in descriptors) {
descriptors[key].value = deepClone(descriptors[key].value, hash);
}
Object.defineProperties(cloned, descriptors);
return cloned;
}
用第三方库(省心稳妥)
生产环境建议用成熟方案:
-
Lodash 的
_.cloneDeep():支持函数(浅拷贝函数引用)、Symbol、undefined、Date、RegExp、Map、Set、循环引用,API 稳定 - immer:不直接做拷贝,而是通过代理实现“看似修改原对象,实则生成新对象”,适合复杂状态管理
示例:
const _ = require('lodash');
const obj = { a: 1, b: undefined, c: () => {}, [Symbol('s')]: 'ok' };
const copy = _.cloneDeep(obj); // ✅ 全部保留(函数仍是原引用)
小结:按场景选方案
如果只跑在较新环境且不含函数 → 用 structuredClone;
需要完全控制、兼容老环境、或必须保留函数引用 → 手写带 WeakMap 的递归;
项目已引入 lodash 或追求开发效率 → 直接用 _.cloneDeep。

















