Vue.js中使用扩展运算符创建对象出现异常行为的问题
为什么修改selectedEmployee时,paginatedEmployees里的对应记录也跟着变?
问题场景
你在Vue项目里写了这段选择员工的代码:
selectEmployee(id) { const employees = [...this.employees]; this.selectedEmployee = employees.find(employee => employee.id === id); }
但通过v-model修改selectedEmployee的值时,发现paginatedEmployees里对应的员工记录也被同步修改了。而paginatedEmployees的初始化代码是这样的:
async fetchEmployees() { this.loading = true; try { const response = await axios.get('/api/employees'); this.employees = response.data.employees; this.paginatedEmployees = _.chunk(this.employees, 10); this.pages = this.paginatedEmployees.length; } catch (e) { this.error = true; this.requestMessage = e.message; } finally { this.loading = false; } }
问题根源
核心原因是JavaScript对象的引用特性,你用的扩展运算符[...this.employees]只是做了一层浅拷贝:
- 扩展运算符复制了数组本身,但数组里的每个
employee对象并没有被真正复制,只是把原对象的引用放进了新数组。 - 而
_.chunk(this.employees, 10)也只是把原employees数组拆分成若干子数组,子数组里的员工对象同样是原数组对象的引用。 - 所以
selectedEmployee实际上指向的是原employees数组里的某个对象,和paginatedEmployees里对应位置的对象是同一个引用。当你修改selectedEmployee的属性时,本质上是在修改这个共享的对象,自然会同步反映到paginatedEmployees里。
解决办法
要解决这个问题,你需要对员工对象做深拷贝,切断和原对象的引用关系。这里提供几种常用方案:
- JSON序列化/反序列化(简单场景适用)
修改selectEmployee方法:
selectEmployee(id) { const targetEmployee = this.employees.find(employee => employee.id === id); // 通过JSON序列化实现深拷贝 this.selectedEmployee = JSON.parse(JSON.stringify(targetEmployee)); }
注意:这种方式不适合包含函数、Symbol、循环引用的对象。
- 使用Lodash的
cloneDeep(推荐,通用场景)
既然你已经在使用Lodash(从_.chunk能看出来),直接用它的深拷贝方法最省心:
selectEmployee(id) { const targetEmployee = this.employees.find(employee => employee.id === id); this.selectedEmployee = _.cloneDeep(targetEmployee); }
- 手动复制对象属性(适用于属性较少的情况)
如果员工对象的属性不多,也可以手动逐个复制属性:
selectEmployee(id) { const targetEmployee = this.employees.find(employee => employee.id === id); this.selectedEmployee = { id: targetEmployee.id, name: targetEmployee.name, // 按需复制其他属性 }; }
这样修改后,selectedEmployee就变成了一个完全独立的对象,修改它的属性就不会影响原数组和paginatedEmployees里的对象了。
内容的提问来源于stack exchange,提问作者enbermudas
相关产品推荐
相关产品推荐

