Vue.js 意外的数据和方法行为
我有一个带有简单模板的 Vue.js 组件
<div @click="createTargets(2)">
text
</div>
脚本文件是
export default {
name: 'test',
data() {
return {
targets: [],
};
},
methods: {
createTargets(targetCount) {
this.targets = [];
var emptyTarget = {
id: null,
};
for (var i = 0; i < targetCount; i++) {
var targetToPush = emptyTarget;
targetToPush.id = i;
console.log(targetToPush.id);
this.targets.push(targetToPush);
console.log(this.targets);
}
return {};
},
},
}
当我单击
text
时,我得到输出
0
[{"id":1},{"id":1}]
1
[{"id":1},{"id":1}]
我不明白为什么会发生这种情况。
我希望
0
[{"id":0}]
1
[{"id":0},{"id":1}]
有什么想法吗?
答案其实很简单,对象只初始化一次,即在将其分配给变量时。如果将此变量分配给新变量,则将同一对象引用分配给新变量。更新 Object1 将更新 Object2,反之亦然。
为了避免此行为,您可以在使用新的扩展运算符初始化 Object2 时创建对象的副本:
const targets = [];
const common = { commonProp: 'test' };
for (let i = 1; i <= count; i++) {
const target = { ...common, id: i };
targets.push(target);
}
this.targets = targets;
请注意,应避免在循环中改变组件的状态。即使渲染循环已优化并且实际上不会渲染
count
次,但最好还是按照示例仅改变一次属性。
另请注意,嵌套对象的行为方式相同。上述解决方案称为浅拷贝,相反,深拷贝将以递归方式抓取您的对象以复制子对象/数组。
const common = {
commonProp: { a: 1, b: 2 }
};
const object1 = { ...common, id: 1 };
const object2 = { ...common, id: 2 };
object1.commonProp.a = 2;
console.log(object1); // { commonProp: { a: 2, b: 2 } }
console.log(object2); // { commonProp: { a: 2, b: 2 } }
为了避免此问题,您可以使用库来深度复制对象/数组,或者创建一个类或工厂函数,每次调用时都会返回一个新对象。
// factory
const createTarget = id => ({
commonProp: { a: 1, b: 2 },
id,
});
// class
class Target {
constructor(id) {
this.id = id;
this.commonProp = { a: 1, b: 2 };
}
}
for (let i = 1; i <= count; i++) {
const target = createTarget(i); // or new Target(i);
targets.push(target);
}
我希望这个解释能帮助您更好地理解这个概念。
祝你好运 ;)
Please be warned that if you log objects in the latest versions of Chrome and Firefox what you get logged on the console is a reference to the object, which is not necessarily the 'value' of the object at the moment in time you call
console.log()
, but it is the value of the object at the moment you open the console
Don't use
console.log(obj)
, useconsole.log(JSON.parse(JSON.stringify(obj)))
您可以打印数组值(而不是引用):
for (var i = 0; i < targetCount; i++) {
var targetToPush = emptyTarget;
targetToPush.id = i;
console.log(targetToPush.id);
this.targets.push(targetToPush);
// like this (es6 way):
console.log([...this.targets]);
// or like this (old way):
console.log(this.targets.slice());
}
当您
console.log(this.targets)
时,您直接打印变量引用,并且它的值将在下一个循环中改变,因此它也将在浏览器控制台中更改。
当您
console.log([...this.targets])
时,您正在打印该给定循环交互的数组值(而不是引用),并且它们将保持不变,即使数组稍后发生变化。