-1

When I create new Array(9) it doesn't seem to be actually creating new arrays because when I attempt to mutate single array instances using take, it mutates all the arrays. Clearly they're each referencing the same array rather than being their own new Array, but why? And how do I fix this? I've tried Array.prototype.slice() in various places, but all to no avail.

const Board = (fillWith = null) => ({
    winner: null,
    squares: new Array(9).fill(fillWith),
    winningSquares: []
});

const game = new Board( new Board() );

const take = (iA, iB, token) => {
  game.squares[iA].squares[iB] = token;
}

take(0,0,'x');
take(8,1,'o');

game.squares.map( (miniboard, i) => console.log({[i]: miniboard.squares}))

Expected Result

{ 0: [ 'x', null, null, null, null, null, null, null, null ] }
{ 1: [ null, null, null, null, null, null, null, null, null ] }
{ 2: [ null, null, null, null, null, null, null, null, null ] }
{ 3: [ null, null, null, null, null, null, null, null, null ] }
{ 4: [ null, null, null, null, null, null, null, null, null ] }
{ 5: [ null, null, null, null, null, null, null, null, null ] }
{ 6: [ null, null, null, null, null, null, null, null, null ] }
{ 7: [ null, null, null, null, null, null, null, null, null ] }
{ 8: [ null, 'o', null, null, null, null, null, null, null ] }

Actual Result

{ 0: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 1: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 2: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 3: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 4: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 5: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 6: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 7: [ 'x', 'o', null, null, null, null, null, null, null ] }
{ 8: [ 'x', 'o', null, null, null, null, null, null, null ] }

UPDATE:

Okay, this has been marked a duplicate of , and some have complained it's been answered a gazillion times. I get it. It feels very familiar, and I'm fully aware that objects and arrays are copied by reference which is why I've attempted to use the new operator for creating new boards. I've also tried the Array.from solution referenced, but that didn't help either. Maybe there's something else going on here and the answer will come to me in the morning, but for now here's a reference to the updated code I tried (but did not work) just to show that I did try what has been suggested as the answer to my "duplicate" question.

const Board = (fillWith = null) => ({
    winner: null,
    squares: Array.from({length: 9}, () => fillWith),
    winningSquares: null
});
Chris Geirman
  • 9,474
  • 5
  • 37
  • 70
  • Man, seriously 4K rep and such questions... objects are passed by refrence in Javascript - that's why nested arrays are mutating, among other things. That's also why people use deepClone or Immutable.js – c69 Nov 15 '17 at 06:59
  • Please look more carefully at the code before you knee jerk react. I'm aware objects are passed by reference. I'm using the `new operator` which should return a `new object` according to the MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new – Chris Geirman Nov 15 '17 at 07:07
  • @ChrisGeirman Even your updated code is still facing the same issue. The reason the code is updating all the index is `const game = new Board( new Board() );`. Here the inner `Board` in invoked once and its reference is being passed to outer `Board`. Try below `let game = Board(); game.squares = game.squares.map(() => Board());` This way, for each index you are getting new reference. – Hassan Imam Nov 15 '17 at 14:02
  • 1
    @HassanImam thank you, you're exactly right. I knew I was missing something obvious. If you want to rewrite your comment as an answer, I'll mark it as the correct answer. – Chris Geirman Nov 15 '17 at 14:53

1 Answers1

1

fill gets a single instance and with it fills all rows. So your all rows refer to the same instance and because array is a reference type you have only on reference in each row. Instead of fill use map to return for each row its own array.

Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112