深拷贝与浅拷贝的区别
浅拷贝:只复制对象的第一层属性。如果属性值是引用类型(如对象、数组),拷贝的是它的内存地址,新旧数据会互相影响。
深拷贝:递归复制对象的所有层级,生成一个完全独立的新对象,新旧数据互不影响。
-
浅拷贝(Shallow Copy)
做了什么:创建一个新对象,将原对象的基本类型属性复制一份,但对于引用类型属性,只复制它的引用(指针)。
在 Vue 中的表现:
javascript
data() {
return {
user: {
name: '张三',
info: { age: 18 }
}
}
},
methods: {
handleCopy() {
// 使用展开运算符进行浅拷贝
const newUser = { ...this.user };// 修改基本类型(第一层),原数据不受影响
newUser.name = '李四';
console.log(this.user.name); // 输出 '张三'// 修改引用类型(深层),原数据会跟着变!
newUser.info.age = 20;
console.log(this.user.info.age); // 输出 20 原数据被意外修改了
}
}
常见的浅拷贝方式:
展开运算符:{ ...obj } 或 [...arr]
Object.assign({}, obj)
Array.prototype.slice()、Array.prototype.concat() -
深拷贝(Deep Copy)
做了什么:完整地复制整个对象结构,在内存中开辟一块全新的空间,与原对象彻底“断开关联”。
在 Vue 中的表现:
javascript
methods: {
handleDeepCopy() {
// 使用 JSON 方法进行深拷贝(注意:有局限性)
const newUser = JSON.parse(JSON.stringify(this.user));// 修改深层属性,原数据纹丝不动
newUser.info.age = 20;
console.log(this.user.info.age); // 输出 18 完全独立
}
}
常见的深拷贝方式:
JSON.parse(JSON.stringify(obj)):最常用,但有缺陷(无法拷贝函数、undefined、Symbol、循环引用等)。
structuredClone(obj):现代浏览器的原生 API,功能比 JSON 方法强大,支持 Date、Map、Set 等,但仍不支持函数。
lodash.cloneDeep(obj):第三方库,功能最全面、最可靠,几乎能处理所有情况。 -
在 Vue 中的实际应用场景
场景一:编辑弹窗(必须用深拷贝)
这是最常见的坑。点击编辑时,如果直接把 row 对象赋值给表单,修改表单会直接改掉列表数据。
javascript
// 错误做法(浅拷贝)
this.editForm = this.row; // 修改 editForm 会直接污染列表
// 正确做法(深拷贝)
this.editForm = JSON.parse(JSON.stringify(this.row));
// 或 this.editForm = _.cloneDeep(this.row);
场景二:组件 Props(视情况使用)
父组件传下来的 props 不建议直接修改。如果你需要基于它做计算,用浅拷贝就够了(只要不改深层)。
javascript
props: ['config'],
computed: {
localConfig() {
// 只改第一层,用浅拷贝即可
return { ...this.config, visible: true };
}
}
场景三:Vuex 状态修改(必须用深拷贝)
在 mutations 或 actions 中,永远不要直接修改 state 中的引用类型,除非你调用 Vue 提供的变更方法(如 Vue.set)。
javascript
// 从 state 取出数组,想 push 新元素
const newList = state.list; // 这是引用
newList.push(item); // 虽然可以,但不符合规范
// 应该深拷贝一份再操作,最后重新赋值(或使用 Vue.set)
const newList = JSON.parse(JSON.stringify(state.list));
newList.push(item);
浙公网安备 33010602011771号