浅拷贝仅复制第一层属性引用,嵌套对象共享内存地址,修改副本会意外影响原对象;排查看“改B导致A变”,修复需用深拷贝方案。

浅拷贝只复制对象第一层属性的引用,嵌套对象仍共享内存地址,修改副本会意外影响原对象。排查关键看是否出现“改了B,A也变了”的现象,修复需明确使用深拷贝方案。
识别浅拷贝导致的副作用
常见触发场景包括:
- 使用 Object.assign({}, obj)、{...obj} 或 Array.prototype.slice() 处理含对象/数组的嵌套结构
- 修改拷贝后的子属性(如 copy.user.profile.name = 'new'),原对象对应字段同步变化
- 控制台打印原对象和副本,展开后发现内部引用地址一致(Chrome 中显示 [[Target]] 相同)
- 单元测试中,对拷贝数据的操作破坏了原始 fixture 数据
选择合适深拷贝方式
不同场景适用不同方法,不盲目用 JSON 方案:
- 简单纯数据对象(无函数、undefined、Date、RegExp、循环引用):用 JSON.parse(JSON.stringify(obj)),轻量但有局限
- 需要兼容性或可控序列化:用 Lodash 的 _.cloneDeep(obj),健壮且处理边界情况完善
- 现代环境 + 无特殊类型:尝试 structuredClone(Chrome 98+、Firefox 94+、Node.js 17.0+),原生高效,支持 Map/Set/Date 等
- 自定义逻辑(如忽略某些字段、转换值):手写递归函数,控制遍历深度与类型判断
验证深拷贝是否生效
不能只看表层相等,要检查嵌套引用是否隔离:
- 对比副本与原对象的嵌套对象是否为不同引用:copy.nested !== original.nested
- 修改副本深层属性后,原对象对应路径值不变:copy.a.b.c = 99; console.log(original.a.b.c); // 应仍为旧值
- 使用 Object.is() 或严格相等比较嵌套对象:Object.is(copy.items[0], original.items[0]) === false
预防性编码习惯
减少后期排查成本:
- 在创建拷贝前,先问一句:“这个对象有没有深层嵌套?会不会被后续修改?”
- 工具函数命名体现语义,如 createSafeCopy() 而非 copy(),强制提醒自己做深拷贝
- TypeScript 项目中,对预期不可变的数据使用 readonly 或 ReadonlyArray 类型标注
- CI 中加入运行时检测(如在开发环境拦截 Object.assign 对嵌套对象的调用并警告)


















