Reputation: 1195
I'm trying to populate a grid of coordinates into a multidimensional array using ES6 nested map methods using this code:
var gridSize = 4;
var regionArray = [];
for (var i = 0; i < gridSize; i++) regionArray.push(new Array(gridSize).fill({start:{x:0, y:0}, end:{x:0, y:0}}));
var regionWidth = canvas.width/gridSize;
var regionHeight = canvas.height/gridSize;
console.log(`regionWidth:${regionWidth} regionHeight:${regionHeight}`)
const hitRegions = regionArray.map((regionRow, i) => {
regionRow.forEach((region, j) => {
region.start.x = j*regionWidth;
region.end.x = j*regionWidth+regionWidth;
region.start.y = (i*regionHeight)+regionHeight;
region.end.y = (i*regionHeight)+regionHeight;
console.log(`>> region i:${i} j:${j} start.x:${region.start.x} end.x:${region.end.x} start.y:${region.start.y} end.y: ${region.end.y}`)
})
console.log('>> regionRow : ',regionRow)
return regionRow;
})
console.log(hitRegions);
The Issue I'm having is that the "regionRow" console.log is returning an array with all of the x values the same for each index.
Meanwhile the values in the ">> region" log above it is logging the correct values.
I'm trying to understand why this is happening and how to fix it..
Upvotes: 0
Views: 245
Reputation: 303
The method Array.prototype.fill()
copies the value to each element.
When you put an object, it just copies the reference over. Meaning that if you update one element, all elements will be changed.
You can simply use a nested for loop to get what you want:
for (let i = 0; i < gridSize; i++) {
const arr = new Array(gridSize);
for (let i = 0; i < gridSize; i++) {
arr.push({ start: { x: 1, y: 1 }, end: { x: 2, y: 2 } });
}
regionArray.push(arr);
}
Upvotes: 0
Reputation: 788
In javascript
everything is passed by reference, for this reason there are methods that do not directly alter the reference (Map
, Filter
, Reduce
) in short, they return a copy of your array and it is modified on that copy.
This also happens with objects! Generally the spread operator is used to make a copy of an object and be able to modify the properties without obtaining side effects, like this:
const obj = {...oldObject}
The problem is when there are several levels in the object to mutate, Using the spread operator does not have a deep copy, therefore if we modify a property in a second level, we will be modifying the main object.
There are several options to fix this, and it will depend on how you are organizing your app:
lodash
(I think it's deprecated) with its cloneDeep
methodImmerJS
To quickly solve the problem you have, I did it using JSON.parse
and JSON.stringify
. This way you can have a copy and modify the deep objects.
The code would look like this:
const hitRegions = regionArray.map((regionRow, i) => {
const newRegionRow = regionRow.map((region, j) => {
var newObject = JSON.parse(JSON.stringify(region))
newObject.start.x = j * regionWidth;
newObject.end.x = j * regionWidth + regionWidth;
newObject.start.y = (i * regionHeight) + regionHeight;
newObject.end.y = (i * regionHeight) + regionHeight;
return newObject
})
return newRegionRow
})
console.log(hitRegions);
This solution is a bit dangerous if your objects have functions or a value that can't be directly converted to json, so be careful.
Upvotes: 1