浅拷贝无法隔离父子组件数据干扰,因只复制外层对象而内部嵌套仍共享引用;正确做法是避免直接修改props,采用JSON.parse(JSON.stringify())、lodash.cloneDeep()或不可变更新策略,或用computed派生+emit通信。

浅拷贝本身不能隔离父子组件的属性传递干扰——它恰恰是干扰的根源。Vue 中 props 传对象时默认就是浅拷贝,子组件拿到的是父组件对象的引用地址,改 props.obj.name 就等于直接改父组件数据。
为什么浅拷贝会“越隔离越混乱”
因为浅拷贝只新建外层容器,内部嵌套结构仍共享内存:
- 父组件传
{user: {name: 'Alice', profile: {age: 30}}} - 子组件用
Object.assign({}, props.data)或{...props.data}浅拷贝 - 得到的新对象
localData的localData.user.profile还是指向原profile的同一块堆内存 - 执行
localData.user.profile.age = 31→ 父组件的user.profile.age立刻变成 31
真正要做的不是“用浅拷贝隔离”,而是“避免依赖浅拷贝”
单向数据流要求子组件不直接修改 props。正确路径是:在子组件初始化阶段就切断引用链,后续所有操作基于独立副本。
- 小数据、纯 JSON 结构(无函数/Date/undefined/Symbol/循环引用):
const localData = ref(JSON.parse(JSON.stringify(props.original))) - 中大型对象或含特殊类型(如 Date、RegExp、Map):
import cloneDeep from 'lodash/cloneDeep'<br>const localData = ref(cloneDeep(props.original))
- 大数据列表(如渲染数百行表格):
跳过深拷贝,改用不可变更新:const localList = ref([...props.list]) // 浅拷贝数组<br>const updateItem = (index, updates) => {<br> localList.value = localList.value.map((item, i) =><br> i === index ? {...item, ...updates} : item<br> )<br>}
更轻量且推荐的替代方案
多数编辑场景无需手动拷贝,用响应式封装 + 事件通信更安全自然:
- 用
computed派生只读视图:const displayUser = computed(() => ({...props.user}))—— 每次访问都生成新对象,避免意外修改 - 编辑时通过
emit通知父组件更新:
子组件不改props.user,而是this.$emit('update:user', {name: 'New'}),由父组件决定如何合并 - 配合
v-model语法糖,自动绑定modelValueprop 和update:modelValue事件,逻辑更清晰


















