I have a Vue.js component with simple template
<div @click="createTargets(2)"> text </div>
and script file is
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 {}; }, }, }
When I click text
, I get output
0 [{"id":1},{"id":1}] 1 [{"id":1},{"id":1}]
I cannot figure out why this is happening.
I would expect
0 [{"id":0}] 1 [{"id":0},{"id":1}]
Any ideas?
Advertisement
Answer
The answer is quite simple really, an object is initialized only once, when it is assigned to a variable. If you assign this variable to a new variable, you are assigning the same object reference to a new variable. Updating Object1 will update Object2 and vice versa.
To circumvent this behavior, you can create a copy of the object when initializing Object2 using the new spread operator:
const targets = []; const common = { commonProp: 'test' }; for (let i = 1; i <= count; i++) { const target = { ...common, id: i }; targets.push(target); } this.targets = targets;
Note that you should avoid mutating your component’s state in a loop. Even though the render loop is optimized and won’t actually render count
times, it’s still better to mutate your property only once as per example.
Also note that nested objects behave the same way. The solution above is called a shallow copy, in contrast, a deep copy will recursively crawl your object to copy sub objects/arrays.
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 } }
To avoid this issue, you can use a library to deep copy an object/array or create a class or factory function that will return a new object every time it is called.
// 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); }
I hope this explanation helped you understand this concept a bit better.
Good luck 😉