展开运算符 {...obj} 仅浅拷贝对象自身可枚举属性,丢失不可枚举属性、Symbol 键、原型链、getter/setter 描述符及嵌套引用,导致状态丢失、方法失效和副作用消失。

展开运算符 {...obj} 拷贝对象时,看似简单,实则会悄悄丢掉不少关键信息。它只复制“看得见、摸得着”的那一部分——也就是对象自身可枚举的属性值,其余一概不管。
不复制不可枚举属性
用 Object.defineProperty() 设置了 enumerable: false 的属性,比如内部状态或私有字段,展开运算符完全无视。这类属性不会出现在 Object.keys() 里,自然也不会被拷贝过去。
- 常见例子:类实例中通过
defineProperty添加的隐藏 ID 或标记位 - 后果:拷贝后丢失状态控制逻辑,可能引发后续判断失效
跳过 Symbol 键和原型链
Symbol 类型的键(如 Symbol('id'))和原型上的方法(比如 toString、自定义的 save())都不会进入新对象。
- 结果是:拷贝后的对象 instanceof 原构造函数为
false - 调用原型方法会报
is not a function - Symbol 属性缺失还可能导致依赖它的 getter/setter 无法读取底层数据而返回
undefined
getter/setter 变成静态值
展开运算符不是复制描述符,而是调用 getter 一次,把返回值当普通数据写进去。set 方法彻底消失,赋值变成静默覆盖。
立即学习“Java免费学习笔记(深入)”;
- 例如
get count() { return this._value }拷贝后只剩一个数字count: 42 - 再给这个
count赋值,不会触发任何逻辑,原对象也不受影响 - 如果 setter 里有校验或副作用(如更新缓存),这些全部丢失
嵌套对象仍共享引用
它只做浅拷贝,所有嵌套的对象、数组、日期、正则等,都只是复制了引用地址。
- 改
copy.user.name,original.user.name同步变 - 哪怕只有一层嵌套,风险已经存在;多层嵌套时更难排查
- 这种“看似独立、实则连通”的行为,常在表单提交、状态重置等场景引发意外副作用


















