一、使用Object.assign
Object.assign(this.panelObj, matchedItem);
-
功能:将
matchedItem的所有可枚举属性复制到this.panelObj对象中(浅拷贝)。如果属性已存在,则会被覆盖;如果不存在,则会被添加。 -
响应式问题:在Vue 2中,如果
matchedItem中有新属性(即this.panelObj原来没有的属性),那么这些新属性不会被Vue响应式系统追踪。这意味着,如果你在模板中使用了这些新属性,当它们改变时,视图不会更新。 -
适用场景:当你确定
this.panelObj已经具有matchedItem中的所有属性(即只是更新已有属性)时,可以使用。或者,在Vue 3中,由于使用了Proxy,可以直接使用Object.assign,因为Vue 3的响应式系统可以检测到新属性。
二、使用$set逐个属性设置
Object.keys(matchedItem).forEach(key => { this.$set(this.panelObj, key, matchedItem[key]); });
-
功能:遍历
matchedItem的每个属性,并使用Vue的$set方法将其添加到this.panelObj中。$set方法会确保属性被添加为响应式属性,即当属性值变化时,视图会更新。 -
响应式处理:无论
this.panelObj原来是否具有该属性,使用$set都会确保该属性是响应式的。如果属性已存在,$set也会更新它,并触发响应式更新。 -
适用场景:在Vue 2中,当需要向响应式对象添加新属性时,必须使用
$set(或Vue.set)来确保新属性也是响应式的。
主要区别
-
响应式处理:
Object.assign不会将新属性转换为响应式,而$set会。 -
性能:
Object.assign是一次性操作,而$set是逐个属性设置,如果属性很多,可能会稍微慢一些。 -
Vue版本:在Vue 2中,推荐使用
$set来添加新属性;在Vue 3中,由于响应式系统基于Proxy,直接使用Object.assign也可以触发响应式更新。
示例说明
假设我们有一个Vue组件,其中panelObj是一个响应式对象,初始为空:
data() { return { panelObj: {} }; }
然后我们有一个matchedItem对象:
matchedItem = { name: 'Alice', age: 30 };
使用Object.assign
Object.assign(this.panelObj, matchedItem);
此时,this.panelObj会变成{ name: 'Alice', age: 30 }。但是,如果panelObj原本没有这些属性,那么在Vue 2中,name和age这两个属性不是响应式的。这意味着,如果你在模板中使用了{{ panelObj.name }},然后以后修改了this.panelObj.name,视图不会更新。
使用$set
Object.keys(matchedItem).forEach(key => { this.$set(this.panelObj, key, matchedItem[key]); });
这样设置后,this.panelObj同样变成{ name: 'Alice', age: 30 },并且每个属性都是响应式的。以后修改this.panelObj.name,视图会更新。
三、Object.assign() 简介
Object.assign() 方法用于对象的合并,将所有可枚举属性的值从一个或多个源对象复制到目标对象。
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。

注意:returnedTarget时target的引用。
const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
另外,如果将数组做为源对象,目标对象为{},那么结果可能会出乎你的意料。
const menuIds = [3,17] const me = Object.assign({}, menuIds) console.log(me) // {0: 3, 1: 17}
menuIds:

me:

注意点
(1)浅拷贝
Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
const obj1 = {a: {b: 1}}; const obj2 = Object.assign({}, obj1); obj1.a.b = 2; obj2.a.b // 2
上面代码中,源对象obj1的a属性的值是一个对象,Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。
(2)同名属性的替换
对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。
const target = { a: { b: 'c', d: 'e' } } const source = { a: { b: 'hello' } } Object.assign(target, source) // { a: { b: 'hello' } }
上面代码中,target对象的a属性被source对象的a属性整个替换掉了,而不会得到{ a: { b: 'hello', d: 'e' } }的结果。这通常不是开发者想要的,需要特别小心。
项目案例:
从父页面传递过来的集合:


save(edit) { this.$refs['form'].validate((valid) => { if (valid) { this.dataList.forEach(item => { let data = Object.assign( edit, { supplyId: item.supplyId, prepareId: item.id }); console.log(edit) console.log(data) send.saveSendForPrepare(data).then(response => { if (response.success) { this.$message.success('恭喜你,保存成功'); this.returnMessage(); this.returnMessage1(); } else { this.$message.error(response.msg); } }).catch(error => { this.$message.error('抱歉,保存失败'); console.log(error); }).finally(() => { this.dialogFormVisible = false; }) }) } }); }
第一次遍历,edit的值为:

data的值为:

第二次遍历edit的值为:

data的值为:

由上面发现,data是edit的引用,两次遍历过程中,Object.assign合并后返回同一个对象edit,即第二次遍历后的edit覆盖了第一次遍历时的edit值,
原因分析:
当执行以下代码:
let data = Object.assign( edit, {
supplyId: item.supplyId,
prepareId: item.id
});
由于data是edit的引用,所以当第一次遍历数组时,edit为{prepareId:708,supplyId:913},此时data的值与edit的值是一样的。当第二次遍历数组时,edit的两个属性prepareId和supplyId的值被覆盖,变为{prepareId:707,supplyId:913},Object.assign拷贝得到的是这个对象edit的引用,当第二次执行Object.assign时,第一次data的值也跟着发生了变化。
解决方法:如果希望合并后返回一个新对象,而不是原来的对象edit,对一个空对象合并。
save(edit) {
this.$refs['form'].validate((valid) => {
if (valid) {
this.dataList.forEach(item => {
let data = Object.assign({}, edit, {
supplyId: item.supplyId,
prepareId: item.id
});
console.log(edit)
console.log(data)
send.saveSendForPrepare(data).then(response => {
if (response.success) {
this.$message.success('恭喜你,保存成功');
this.returnMessage();
this.returnMessage1();
} else {
this.$message.error(response.msg);
}
}).catch(error => {
this.$message.error('抱歉,保存失败');
console.log(error);
}).finally(() => {
this.dialogFormVisible = false;
})
})
}
});
}
第一次遍历,edit的值为:

data的值为:

第二次遍历edit的值为:

data的值为:

由上面发现,edit的值一直保持不变,Object.assign合并后返回一个新对象。
总结:在forEach循环中,当用Object.assign() 方法合并对象时,最好对一个空对象合并,如果合并到变量(对象)上,那么每次的循环时,合并后的对象都是一样的。
浙公网安备 33010602011771号