深拷贝默认不处理不可枚举属性是主动取舍而非遗漏;主流工具如json.stringify、structuredclone、lodash clonedeep及fast-copy标准模式均跳过,仅fast-copy strict模式、手写描述符遍历或php deepcopy可完整保留。

深拷贝默认不处理不可枚举属性,这不是遗漏,而是多数方案主动选择跳过——因为它们只遍历可枚举自有属性(如 Object.keys() 或 for...in),而像 Object.defineProperty(obj, 'secret', { value: 42, enumerable: false }) 定义的字段,天然被过滤掉。
哪些工具会忽略不可枚举属性?
主流方案基本都如此:
- JSON.stringify() → parse():完全无视不可枚举属性,也不处理 Symbol 键
-
structuredClone():仅复制可枚举自有属性,跳过
enumerable: false和原型链上的属性 -
Lodash _.cloneDeep():默认不拷贝不可枚举属性;需配合
_.getOwnPropertyDescriptors()手动扩展才能覆盖 -
fast-copy(标准模式):为性能默认跳过,仅在
strict: true下启用完整描述符拷贝
如何检测一个属性是否不可枚举?
不能依赖 for...in 或 Object.keys(),它们天生排除不可枚举项。正确方式是结合描述符检查:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
Object.getOwnPropertyNames(obj)获取所有自有键(含不可枚举字符串键) - 用
Object.getOwnPropertySymbols(obj)获取所有自有 Symbol 键 - 再对每个键调用
Object.getOwnPropertyDescriptor(obj, key),查看enumerable字段值
真正保留不可枚举属性的深拷贝路径
只有明确支持“属性描述符完整复刻”的方案才能可靠还原:
-
fast-copy 开启 strict 模式:
copy(obj, { strict: true })会调用Object.getOwnPropertyDescriptors()并用Object.defineProperties()重建 -
手写递归 + 描述符遍历:替换常规遍历为
Object.getOwnPropertyNames() + getOwnPropertyDescriptors(),再逐个defineProperty或defineProperties - PHP 的 DeepCopy 库:通过反射获取全部属性(含私有、受保护、不可枚举),天然支持,无需额外配置
为什么多数库不默认保留?
不是做不到,而是有意取舍:
- 性能开销:获取并重建描述符比简单遍历慢 3–5 倍
-
语义模糊:不可枚举属性常用于内部状态(如 React 的
$$typeof)、代理标记或私有字段,拷贝可能破坏封装或引发意外行为
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










