浅拷贝修改嵌套属性会污染原对象,因其仅复制第一层属性的值或引用,嵌套的引用类型仍共享堆内存地址;Object.assign、展开运算符等方法均属此类,修改副本嵌套属性即直接操作共享内存,导致原对象同步变化。

浅拷贝在修改嵌套属性时会污染原始对象,根本原因是它只复制第一层属性的值或引用,对嵌套的对象、数组等引用类型,复制的是内存地址而非实际内容。
为什么嵌套属性修改会影响原对象
JavaScript 中对象和数组属于引用类型,存储在堆内存中,变量保存的是指向该内存的地址。浅拷贝(如 Object.assign()、展开运算符 {…obj}、Array.prototype.slice())仅复制这一层地址。新旧对象的嵌套结构仍指向同一块堆内存。
- 修改新对象中嵌套对象的属性,等于直接操作堆中那块共享数据
- 原对象读取同一地址,自然看到被改动后的值
- 这不是“意外”,而是浅拷贝的设计本质——它本就不承诺隔离深层数据
典型触发场景示例
以下代码清晰暴露问题:
含嵌套对象:
立即学习“Java免费学习笔记(深入)”;
const user = { name: 'Alice', profile: { age: 30, city: 'Beijing' } };<br>const copy = { ...user };<br>copy.profile.city = 'Shanghai';<br>console.log(user.profile.city); // 'Shanghai' —— 原对象被改
含嵌套数组:
const data = { id: 1, tags: ['js', 'react'] };<br>const clone = Object.assign({}, data);<br>clone.tags.push('vue');<br>console.log(data.tags); // ['js', 'react', 'vue'] —— 原数组已变
哪些方法看似“复制”实则只是引用共享
这些操作根本不是拷贝,只是赋值引用,副作用最直接:
- let copy = original; —— 完全共用同一对象
- const copy = original.arr[0]; —— 取出的仍是嵌套对象引用
- 函数参数接收对象 —— 参数名本身就是一个新变量,但值仍是传入对象的地址
如何避免这类副作用
关键看数据结构深度和运行环境:
- 一维简单对象/数组 → 用展开运算符或 Object.assign() 安全
- 含一层嵌套(如对象里有对象或数组)→ 手动逐层解构,例如:{ …obj, nested: { …obj.nested } }
- 多层嵌套或不确定结构 → 优先使用 structuredClone()(现代浏览器及 Node.js ≥18.16 支持)
- 需兼容老旧环境 → 引入 Lodash 的 _.cloneDeep(),处理循环引用、Date、RegExp 等更健壮
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xinjizixun/123839.html