javascript深拷贝默认忽略symbol属性,需用reflect.ownkeys获取全部键(含symbol),再通过object.getownpropertydescriptor和object.defineproperty手动复制属性描述符;lodash.clonedeep已内置支持。

JavaScript 中深拷贝默认不处理 Symbol 类型的属性,因为大多数内置方法(如 JSON.stringify、Object.assign、扩展运算符)会忽略 Symbol 键。要正确复制 Symbol 属性,必须显式获取并遍历对象的所有 Symbol 键(包括不可枚举的),再手动赋值到新对象中。
使用 Reflect.ownKeys() 获取所有键(含 Symbol)
Reflect.ownKeys(obj) 返回对象自身所有键(字符串 + Symbol),是实现 Symbol 深拷贝的关键起点。它比 Object.keys() 或 Object.getOwnPropertyNames() 更全面。
- 先用
Reflect.ownKeys()获取全部键 - 对每个键,用
Object.getOwnPropertyDescriptor()提取描述符(含value、get/set、可枚举性等) - 递归深拷贝
value(如果是对象/数组等引用类型) - 用
Object.defineProperty()将属性(含 Symbol 键)精确复制到新对象
手动递归实现(支持 Symbol 的深拷贝函数)
下面是一个简化但可用的深拷贝函数示例,能保留 Symbol 键及其属性特性:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const clone = Array.isArray(obj) ? [] : {};
// 复制所有键:字符串 + Symbol
for (const key of Reflect.ownKeys(obj)) {
const desc = Object.getOwnPropertyDescriptor(obj, key);
const value = desc.value;
// 递归深拷贝值
const clonedValue = (typeof value === 'object' && value !== null)
? deepClone(value)
: value;
// 保持原有属性描述符(如 writable、enumerable、configurable)
Object.defineProperty(clone, key, {
...desc,
value: clonedValue
});
}
return clone;
}
注意:该实现保留了 Symbol 键、属性的可枚举性、访问器(getter/setter)和其它 descriptor 特性,但不处理循环引用。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
借助第三方库(如 lodash)
lodash.cloneDeep() 默认支持 Symbol 属性的拷贝(自 v4.0.0 起),内部已处理 Reflect.ownKeys 和 descriptor 复制逻辑。
- 安装:
npm install lodash - 使用:
const cloned = _.cloneDeep(originalObj); - 验证:
cloned[Symbol('test')] === originalObj[Symbol('test')](值相等,且 Symbol 键存在)
适合生产环境,省去手写兼容逻辑的成本。
注意事项与限制
Symbol 拷贝本身不会“克隆” Symbol 值——Symbol 是唯一值,拷贝后仍是同一个 Symbol(即 cloned[s] === original[s])。这是预期行为,不是 bug。
- 若需真正“复制” Symbol(生成新 Symbol),需额外记录映射关系并替换,但通常无此需求
- WeakMap、WeakSet、函数、正则、Date 等特殊对象需单独处理,基础递归版本不覆盖
- Symbol 作为对象键时,
for...in和Object.keys()都不可见,必须依赖Reflect.ownKeys
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










