symbol属性在常规克隆中会被忽略,因其不可枚举且不可序列化;需用object.getownpropertysymbols()获取并手动复制,深克隆时须递归处理值并确保symbol键完整保留。
symbol 类型在对象克隆中是个“隐形陷阱”——它不被常规克隆方法处理,却真实存在于对象属性中。如果你的对象用了 symbol 作键,用 json.parse(json.stringify(obj)) 或 object.assign 克隆,这些 symbol 属性会直接消失;用扩展运算符 {...obj} 同样无法拷贝 symbol 键,因为它们不属于对象的可枚举属性。
Symbol 是什么,为什么克隆时容易丢
Symbol 是 ES6 引入的原始类型,每个 Symbol 值都是唯一且不可复现的。它常被用作对象的“私有键”,比如:
const id = Symbol('user-id');
const user = { name: 'Alice', [id]: 123 };
这个 id 不会被 for...in、Object.keys() 或 JSON.stringify() 捕获,因为它不是可枚举属性,也不可序列化。所以大多数浅克隆/深克隆方案默认忽略它。
如何让 Symbol 属性也被克隆
要真正保留 Symbol 键,必须显式获取并复制它们。关键方法是:Object.getOwnPropertySymbols() —— 它能返回对象自身所有 Symbol 属性的数组。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
克隆时需额外做两件事:
- 遍历
Object.getOwnPropertySymbols(obj)获取所有 Symbol 键 - 用
Object.defineProperty()或直接赋值(newObj[sym] = obj[sym])把 Symbol 属性复制过去 - 注意:
Object.assign()和展开语法都不处理 Symbol,必须手动补上
带 Symbol 的深克隆函数要点
一个健壮的深克隆函数不能只递归普通属性,还得兼顾 Symbol。示例逻辑如下:
- 先创建新对象(
Array.isArray(obj) ? [] : {}) - 用
for...in+hasOwnProperty处理字符串键(含继承链过滤) - 用
Object.getOwnPropertySymbols(obj)获取 Symbol 键,并逐个赋值 - 对每个值递归克隆(包括 Symbol 对应的值,它可能是任意类型)
- 特别注意:Symbol 本身是原始值,直接赋值即可,无需深克隆
实际开发中的建议
多数业务场景下,Symbol 用于内部标识或避免命名冲突,不参与数据传输。但如果确实需要克隆 Symbol 属性:
- 优先使用成熟的库如
lodash.cloneDeep(它已支持 Symbol) - 手写时务必检查
Object.getOwnPropertySymbols返回结果 - 避免依赖
JSON方案——它连undefined、function、RegExp都丢,Symbol 更不在话下 - 测试时加一条:克隆后
Object.getOwnPropertySymbols(newObj).length === Object.getOwnPropertySymbols(oldObj).length
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










