标准深拷贝方法默认不复制不可枚举属性,需用object.getownpropertydescriptors()获取全部自有属性描述符,再通过object.defineproperties()递归定义到新对象以保留enumerable、writable等特性。

JavaScript 中标准的深拷贝方法(如 JSON.parse(JSON.stringify())、结构化克隆 structuredClone() 或主流库如 Lodash 的 cloneDeep)**默认不复制不可枚举属性**,因为它们依赖的是对象的可枚举自有属性(即 for...in、Object.keys() 或 Object.getOwnPropertyNames() 的子集),而不可枚举属性需显式通过 Object.getOwnPropertyDescriptors() 获取。
不可枚举属性需要手动遍历所有自有属性描述符
要保留不可枚举属性,必须获取对象**所有自有属性(包括不可枚举的)的完整描述符**,再逐个定义到新对象上。核心是使用:
-
Object.getOwnPropertyDescriptors(obj):返回包含所有自有属性(含不可枚举)的 descriptor 对象 -
Object.defineProperties(target, descriptors):将 descriptor 批量定义到目标对象 - 对每个 descriptor 中的
value(或get/set)做递归深拷贝
基础深拷贝 + 不可枚举属性支持的实现
以下是一个轻量、可递归处理不可枚举属性的深拷贝函数示例:
function deepCloneWithNonEnumerable(obj) {
if (obj === null || typeof obj !== 'object') return obj;
// 处理 Date、RegExp 等内置类型(可按需扩展)
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const cloned = Array.isArray(obj) ? [] : {};
// 获取所有自有属性描述符(含不可枚举)
const descriptors = Object.getOwnPropertyDescriptors(obj);
for (const [key, desc] of Object.entries(descriptors)) {
// 递归拷贝 value(如果是对象/数组),保持 getter/setter 和 enumerable/writable/configurable
if (desc.value !== undefined) {
desc.value = deepCloneWithNonEnumerable(desc.value);
}
// 注意:不递归处理 get/set 函数体(函数本身不可深拷贝,通常直接引用)
Object.defineProperty(cloned, key, desc);
}
return cloned;
}
✅ 这样就能保留 enumerable: false 的属性,并维持其 writable、configurable 等特性。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
注意 Symbol 键和原型链上的不可枚举属性
上述方法只处理**自有属性**(own properties)。还需注意:
-
Symbol 键属性:
Object.getOwnPropertyDescriptors()默认包含 Symbol 键,无需额外处理 -
原型链上的不可枚举属性:不会被拷贝(深拷贝本就不继承原型),若需复制原型,需额外用
Object.getPrototypeOf()+Object.getOwnPropertyDescriptors()逐层处理(但通常不推荐,易破坏原型语义) - 循环引用:该简易实现未处理,实际项目中建议用 WeakMap 缓存已克隆对象避免爆栈
现代方案:structuredClone 的局限与补充
structuredClone() 是浏览器原生深拷贝 API,但它完全忽略不可枚举属性和属性描述符元信息(只序列化可枚举值 + Symbol 键值,且丢弃 writable、enumerable 等配置)。因此:
- 即使对象有不可枚举属性,
structuredClone(obj)返回的对象里也不存在它们 - 若业务强依赖不可枚举属性(如私有字段标记、内部状态 descriptor),必须手写或使用支持 descriptor 的库(如
klona不支持,flatted也不支持;目前无主流库开箱即用)
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










