因为专注所以专业
助力成长与创新,汇集前沿前端开发观点

2026年了,对象复制后为什么修改第二层,原对象也跟着变?

2026年9月6日 阅读:125

对象复制后修改第二层导致原对象跟着变,根因是 Object.assign 和展开运算符只复制了第一层:内层对象仍指向同一个引用。2026年项目联调时遇到“改嵌套字段,原对象同步变化”的情况,基本都在这一机制内。要不要继续往下处理,取决于你要修改到第几层:只改第一层可以用浅拷贝;需要改第二层以上,就要换用 structuredClone 或不可变更新。

第一层和第二层,差别在哪里

Object.assign(target, ...sources) 会把源对象所有可枚举属性逐个复制到目标对象。遇到原始类型时传值,遇到对象或数组时只传引用。展开运算符 {...obj} 也遵循同一规则。

  • 第一层字段是字符串、数字这类原始类型,新对象和原对象互不影响。
  • 第二层及以上的属性,复制的是引用地址。例如 newObj.params.pageSize = 20,会直接改到 originalObj.params.pageSize。
  • 数组也一样:arrayCopy[0].name = 'x' 会穿透到原数组。

所以判断是不是浅拷贝,不看写了几个等于号,而是看修改路径上是否存在共享的嵌套引用。只要内层对象没有被重建,改动就会越过边界。

先问三个问题,再决定要不要深拷贝

实际开发中不推荐先背结论,按如下顺序判断更稳。

  1. 我要修改到第几层?只改第一层,浅拷贝通常够;要改嵌套字段并保留原对象不变,就必须向深层复制。
  2. 原对象后续还会被使用吗?如果它被多个模块读取或作为全局配置,浅拷贝的深层修改会污染其他页面;如果只用于一次性计算,风险就小很多。
  3. 运行环境允许用原生 API 吗?Node.js 17+ 和较新浏览器支持 structuredClone;在不支持的环境中需要先检测,再决定用递归克隆还是第三方依赖。

顺序很重要:先确定修改深度,再考虑是否值得为隔离付出成本,最后看环境约束。多数“改坏原对象”的案例,走到第一问就能定位。

2026年深浅拷贝方案对比:成本与边界

需要深拷贝时,可先按下表核对各方案的成本和适用边界。这里的周期是维护与联调的经验区间,不是固定值。

  • structuredClone:适合现代浏览器和 Node.js 17+。能处理 Date、Map、Set、RegExp,也会检查循环引用。接入成本约半天;若需要兼容旧 WebView,还要加能力检测和降级,常见区间为 1~2 天。
  • JSON.parse(JSON.stringify(obj)):适合纯 JSON 配置。函数和 undefined 会被忽略,循环引用直接抛错。日常使用成本低,但若数据含 Date,返工区间约半天到一天。
  • 递归克隆:可以自定义 Date、Function、原型,但边界较多。从实现到补测试,常见区间为 1~3 天;后续每增加一种数据类型,还可能叠维护时间。
  • 不可变类库(如 Immer):适合状态更新频繁的全局 Store,通过结构共享减少复制成本。引入依赖并统一协作方式,学习与改造区间为 3~7 天。

从 2026 年前端交付的视角看,structuredClone 是多数项目的优先选,但要不要用它,仍取决于最低运行环境。项目若需要支持旧版安卓 WebView,递归克隆或 polyfill 是更稳妥的路径。

交付现场:一次筛选器配置的“串扰”返工

2026 年上半年,某管理后台项目出现过这类串扰。约束条件:三周交付周期,页面配置由后端一次性返回,项目没引入全局状态管理。做法:同事图方便,用 Object.assign 把接口配置复制到组件 data,再往嵌套的 options 字段上 push 新选项。结果 options 仍是原对象引用,改动污染了源配置,导致另外两个页面读取同一配置时选项重叠。

修这个坑用了两天。按团队复盘,类似浅拷贝误用造成的返工,在联调阶段的常见区间是半天判断错、1~3 天返工;嵌套层级越深、共享页面越多,代价越高。判断数据是否真的“隔离”,标准是:改完后不影响任何外部可见状态,才算拥有它。

适用与不适用边界

浅拷贝适合这些场景:表单初始化时只需要替换默认值的第一层;渲染只读快照且不会修改子结构;或者只想把对象换个变量名,不打算动原内存。浅拷贝成本低,引入深拷贝反而会让逻辑变重。

不适合浅拷贝的场景包括:数据超过两层,后续需要增删改嵌套节点;对象被多个模块共享,任何一方都不该改动公共数据;对象存在循环引用且需要序列化。这时继续用 Object.assign,累积的会是一笔技术债。

深拷贝也不是万能的。高频更新的大对象若整棵克隆,每帧会有几十毫秒到几百毫秒不等的开销(经验区间,随设备性能变化)。如果数据重点在“频繁小幅更新”,更适合用不可变类库的结构共享。

常见问题

改第一层的时候,为什么原对象没变?

因为第一层属性如果是字符串、数字等原始类型,复制时直接赋值,内存里是两份。只有属性值为对象或数组时,复制的才是引用。

展开运算符 {...obj} 算深拷贝吗?

不算。它和 Object.assign 一样只复制第一层,第二层还是引用。想通过展开运算符去隔离多层修改,通常达不到目的。

JSON.parse(JSON.stringify(obj)) 是不是就安全了?

不一定。它只保留 JSON 兼容数据,函数和 undefined 会丢,循环引用会抛错。纯配置数据能用,含 Date、Map 的业务数据需要谨慎。

structuredClone 在 2026 年还需要垫片吗?

现代浏览器与 Node.js 17+ 已内置,但部分旧 WebView 不支持。先检测 typeof structuredClone === 'function',不支持时再降级到递归克隆。

后端返回的配置对象能直接复制后修改吗?

先看你要改第几层。只替换第一级可以浅拷贝;要改嵌套的数组或对象,建议先解构出数据再扩展改动路径,或者使用深拷贝。


代码打开前先问一句:原对象还需要保持独立吗?对齐复制深度与修改意图,能省掉大部分联调返工。只改第一层,浅拷贝就够;要改第二层及以上,直接换 structuredClone 或不可变更新。先跑一次能力检测,再决定降级路径。

有类似的项目需求?
联系我们,获取一对一项目参考方案
获取方案
对这个话题感兴趣?
10 年技术团队,24 小时内出具参考方案
获取方案
准备好开始了吗,
那就与我们取得联系吧!
13370032918
了解更多服务,随时联系我们
请填写您的需求
您希望我们为您提供什么服务呢
您的预算

微信二维码
扫码添加客服微信
专业对接各类技术问题
联系电话
13370032918 (金经理)
电话若占线或未接到、就加下微信
联系邮箱
349077570@qq.com
提交成功
感谢您的信任,我们会尽快与您联系!
为您推荐以下案例