浅拷贝只复制对象自身可枚举属性,忽略不可枚举属性和继承属性;object.assign()与扩展运算符支持可枚举symbol,for...in会遍历原型链,直接赋值为引用共享;需完整拷贝时应手动获取所有自有属性并控制描述符。

浅拷贝本身不关心属性是否可遍历,它只按常规方式读取并复制对象自身的、可枚举的(enumerable)属性值。
浅拷贝默认只处理可枚举属性
JavaScript 中绝大多数浅拷贝方法(如 Object.assign()、扩展运算符 {...obj}、for...in 循环)都基于“可枚举性”来遍历属性。这意味着:
- 不可枚举属性(例如通过
Object.defineProperty()设置enumerable: false的属性)不会被复制; - 继承来的属性(来自原型链)也不会被复制,除非显式遍历原型链;
- Symbol 类型的键若为可枚举,会被
Object.assign()和扩展运算符复制,但for...in不会访问 Symbol 属性。
不同浅拷贝方式对不可遍历属性的实际表现
具体行为取决于所用方法:
-
Object.assign(target, source):复制 source 自身所有可枚举属性(含可枚举的 Symbol),忽略不可枚举属性和原型属性; -
{...source}:行为与Object.assign基本一致,也只复制自身可枚举属性(包括可枚举 Symbol); -
for...in:遍历自身 + 原型链上所有可枚举属性,因此可能意外复制继承来的可枚举属性; - 直接赋值
let b = a:不是拷贝,而是引用共享,不涉及属性遍历逻辑。
如何让浅拷贝包含不可枚举或 Symbol 属性
如果需要更完整的属性覆盖,需手动干预:
- 用
Object.getOwnPropertyNames(obj)获取所有自身属性名(含不可枚举字符串键); - 用
Object.getOwnPropertySymbols(obj)获取所有自身 Symbol 键; - 结合两者,再逐个读取描述符(
Object.getOwnPropertyDescriptor()),判断是否需要复制; - 注意:即使复制了不可枚举属性,新对象中该属性默认仍是可枚举的,除非显式设置
enumerable: false。
实际开发中的建议
多数业务场景下,可枚举性就是设计意图——不可枚举属性常用于内部状态或元信息,本就不该被简单拷贝。若发现浅拷贝后丢失关键属性,应先确认该属性是否被定义为不可枚举,而不是盲目替换拷贝方式。真正需要完整拷贝时,深拷贝或自定义属性遍历才是更稳妥的选择。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











