展开运算符处理深层嵌套对象时并非失效,而是仅执行浅拷贝、不触发响应式深层更新、丢失Symbol/不可枚举属性、高频使用导致性能下降。

展开运算符(...)处理深层嵌套对象时,本身不会“失效”——它总能正确复制可枚举属性,生成新对象。问题在于:**你期待它完成的事,它其实没做,而你误以为它做了**。识别这类“假性失效”,关键不是看语法对不对,而是看行为是否匹配业务意图。
一、你以为它深拷贝,其实它只浅展开
展开运算符对嵌套对象执行的是浅拷贝。内部对象仍共享引用,修改嵌套层会意外影响原对象或合并结果。
- ❌ 错误预期:用
{...obj}修改obj.user.profile.name后,原obj不变,且其他组件读取的也是独立副本 - ✅ 实际行为:
user和profile这两个对象引用未变,改newObj.user.profile.name就等于改obj.user.profile.name - ? 识别信号:调试时发现两个看似独立的对象,修改一处,另一处同步变化;或单元测试中 mock 嵌套对象后,断言失败但看不出哪里被污染
二、你依赖它触发响应式更新,但它不通知深层变更
在 HarmonyOS ArkUI(V1)、Vue 2 或早期 React 状态管理中,展开运算符生成的新对象虽“新”,但若未穿透更新到响应式系统感知的层级,UI 依然不刷新。
- ❌ 错误写法:
this.config = {...this.config, privacy: {...this.config.privacy, autoSave: false}}—— 虽然privacy层被重写,但若@State只观测config一层,Toggle组件仍不会响应 - ✅ 正确做法:配合
@Observed+@ObjectLink,或直接替换整个嵌套路径(如this.config = Object.assign({}, this.config, { privacy: Object.assign({}, this.config.privacy, { autoSave: false }) })) - ? 识别信号:控制台打印值已更新,但 UI 组件无反应;使用
console.log(JSON.stringify(obj))看似生效,但绑定字段没重绘
三、你用它合并配置,却忽略了 Symbol 和不可枚举属性丢失
展开运算符只遍历对象自身的可枚举属性,自动跳过 Symbol 键(除非显式调用 Object.getOwnPropertySymbols())和 enumerable: false 的属性。
- ❌ 隐患场景:API 返回对象含
Symbol('meta')存校验信息,或通过Object.defineProperty设置了私有配置字段__version(enumerable: false),用{...res}合并后这些元数据全部消失 - ✅ 替代方案:需深拷贝时用
structuredClone()(现代环境);需保留非枚举属性时,手动Object.getOwnPropertyDescriptors()+Object.defineProperties() - ? 识别信号:某些功能突然失灵(如权限校验、版本比对),但日志显示主数据正常;检查对象属性时发现
Object.keys(obj)和Reflect.ownKeys(obj)输出不一致
四、你在循环中高频展开,却没意识到性能已崩塌
每次展开都触发完整遍历 + 新对象分配。当嵌套结构大(如 5 层+、每层数十字段)、且在渲染循环或高频事件中反复执行时,GC 压力陡增,页面卡顿。
- ❌ 危险模式:
list.map(item => ({...item, updatedAt: Date.now()}))处理上千条记录;或在onScroll中不断{...state, visibleRange: [start, end]} - ✅ 优化方向:对只读展示场景,用 memoization 缓存展开结果;对状态更新,改用不可变库(如 immer)或仅更新必要字段(
setState(prev => ({...prev, a: {...prev.a, b: newValue}}))) - ? 识别信号:Performance 面板显示大量 “Minor GC”;React Profiler 中某组件 render 时间随列表长度线性增长;Chrome 内存快照里出现大量重复的扁平化对象实例










