0
const queenThreat = function (board) {
  let collision = false;
  let newBoard = board.slice(0);
  // Horizontal
  let horizontal = newBoard[whiteQueen[0]];
  horizontal.splice(5, 1, 0);
  collision = horizontal.includes(1)
  return board;

// Original array

[ [ 0, 0, 0, 0, 0, 1, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 1, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ] ]
// Original array after above code despite cloning the array and only accessing the cloned array

[ [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 1, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0, 0, 0 ] ]

I've cloned my array using slice(), accessed it instead of the original array under //Horizontal, and yet when I return the original array it's STILL modified. What am I doing wrong? I've tried every way to create a clone of the array and they all somehow modify the original despite never accessing it.

xynon
  • 59
  • 4
  • 2
    Search for: ["\[javascript\] array shallow clone"](https://stackoverflow.com/search?q=%5Bjavascript%5D+array+shallow+clone). There are _many_ duplicates. – user2864740 Feb 28 '20 at 23:07
  • 1
    The first paragraph of https://stackoverflow.com/a/597726/2864740 seems nice an succinct (arrays are objects too). – user2864740 Feb 28 '20 at 23:10
  • 1
    In an array of numbers, using `.slice()` will result in a new array that, no matter how its modified, won't affect the original array. But you have an array *of arrays*. Specifically, an array of *references to* arrays. You do copy the array, but the new one has the same references as the old one - to the same data. They both still point to the same data. You'll need new references to new copies of all the inner arrays if you want them to not change. – Klaycon Feb 28 '20 at 23:19

3 Answers3

2

This is because .slice() only performs a shallow copy, therefore some of the values are still referenced from the original array. Please see more detailed explanation in the answers to this question: What is the difference between a shallow copy and a deep copy with JavaScript arrays?

curiousdev
  • 626
  • 8
  • 24
2
let newBoard = JSON.parse(JSON.stringify(board));

This did the trick. I figured it had something to do with being a shallow copy, but then I'm not sure what the point of creating a copy of the same array is if you can't separately modify it?

xynon
  • 59
  • 4
  • 1
    Perhaps an example would help: If you have every student array that contains the same teacher data, you may only want to update the teacher data once. Creating a new student array from another student array, would accomplish that, without breaking the teacher linkage. Your question uses a multi-dimensional array that is uniform in dimensions, like a matrix; however, that isn't always the case. An array can have some elements being string, numeric, and other object/arrays that are not uniform in dimension or type. Had you edited one of those non-object elements, it would have been mutable. – Mike Feb 28 '20 at 23:19
  • 1
    You *can* separately modify it. You can set `newBoard[0] = someNewData` without it modifying `board`. This is what it means to be a shallow copy. But since both the original and copy contain *references to the same arrays* that haven't been cloned (all the inner arrays), accessing those references and modifying *their* data still modifies it for both. – Klaycon Feb 28 '20 at 23:20
  • Ahh that makes sense. Thanks! – xynon Feb 28 '20 at 23:22
1

Array.prototype.slice() does a shallow clone. Which means if the array is contains objects, the clone will be referring to the same object.

board is a 2-dimensional array. Each element in this array is an array. board.slice() provides a shallow copy of the board. If you do something like newBoard[0] = ...., original board doesn't change. But each element within newBoard, for example newBoard[0] is still referring to the same object as before board[0]. Any change in the form of newBoard[0][0] = ... will also update board[0][0].

In order to fix this, you'd need to deep clone. There are libraries performing this already. But if your use case is just 2-dimensional array, you could do something like this:

newBoard = board.map(row => row.slice());