JavaScript深拷贝需用Reflect.ownKeys获取所有自有键(含Symbol),再通过Object.getOwnPropertyDescriptor和Object.defineProperty保留属性特性,Symbol值须原样引用不可重建。

JavaScript 深拷贝要正确复制 Symbol 类型的属性,核心是:不能依赖只处理字符串键的方法(如 for...in、Object.keys() 或 JSON.stringify()),而必须显式获取并处理 Symbol 键。
用 Reflect.ownKeys 统一获取所有自有键
Reflect.ownKeys(obj) 是最推荐的起点——它天然返回对象所有**自有属性键**,包括可枚举/不可枚举的字符串键,也包括所有自有 Symbol 键(无论是否可枚举)。
- 它不包含继承属性,也不包含原型链上的 Symbol
- 返回顺序与属性定义顺序一致,便于可预测处理
- 避免手动拼接
Object.keys(obj)和Object.getOwnPropertySymbols(obj)
逐个读取并赋值,保持 Symbol 值原样引用
Symbol 是原始值,不具备“深拷贝”意义;拷贝时必须复用原 Symbol 实例,不可重建。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 直接使用方括号语法:
clone[key] = obj[key],对 Symbol 键完全有效 - 禁止写成
clone[key.toString()] = ...或Symbol(key.description),这会创建新 Symbol,失去唯一性和语义 - 若需保留属性特性(如
enumerable: false或configurable: false),应配合Object.getOwnPropertyDescriptor(obj, key)+Object.defineProperty(clone, key, descriptor)
在递归深拷贝中嵌入 Symbol 处理逻辑
标准递归深拷贝函数常只遍历 for...in 或 Object.keys(),导致 Symbol 键被跳过。需将 Symbol 支持内建为流程一部分:
立即学习“Java免费学习笔记(深入)”;
- 对每个
key(来自Reflect.ownKeys(obj)),先获取其描述符 - 若值为对象或数组,递归调用深拷贝函数;否则直接赋值
- 对
Date、RegExp、Map、Set等特殊类型单独判断,再统一处理 Symbol 键 - 用
WeakMap解决循环引用时,也要把 Symbol 键纳入缓存键的判断范围
注意 Object.assign 的局限性
Object.assign() 虽然能拷贝 Symbol 属性,但它只处理**可枚举**的自有属性——不可枚举的 Symbol 键(如通过 Object.defineProperty 设置 enumerable: false)会被忽略。
- 因此它不适合用于需要完整保有属性特性的深拷贝场景
- 仅适合简单浅拷贝且不关心不可枚举 Symbol 的情况
- 不能替代
Reflect.ownKeys+getOwnPropertyDescriptor的组合方案

















