javascripttypescriptshallow-copy

Unexpected values in two-dimensional array


This is probably a duplicate question but I didn't know how to search for it.

Can someone explain the bevior from the code snippet to me?

I am trying to iterate over a 2-dimensional array, setting each value to the index of the containing row. Yet all values are somehow set to the last row's index.

const string1 = "abc";
const string2 = "abcd";

const matrix = new Array(string1.length).fill(new Array(string2.length).fill(0));

for (let i = 0; i < string1.length; i++) {
  for (let j = 0; j < string2.length; j++) {
    console.log(i);
    matrix[i][j] = i;
  }
}

console.log(matrix);

Output:

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

Expected output:

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

Solution

  • See the documentation:

    fill() changes all values of an array to a static value. [...] Note all elements in the array will be this exact value: if value is an object, each slot in the array will reference that object.

    That means in each of your rows you will reference the same object (= Array, remember: arrays are objects in JavaScript) meaning you always change the same array resulting in the last change being the one you can observe by printing it.

    const string1 = "abc";
    const string2 = "abcd";
    
    const matrix = new Array(string1.length).fill(new Array(string2.length).fill(0));
    
    for (let i = 0; i < string1.length; i++) {
      for (let j = 0; j < string2.length; j++) {
        matrix[i][j] = i;
      }
    }
    
    console.log(JSON.stringify(matrix));
    // Prove that they are actually the same reference => same object
    console.log(matrix[0] === matrix[1]) // true

    You could use the following approach to initialize the array.

    const string1 = "abc";
    const string2 = "abcd";
    
    const matrix = [...new Array(string1.length)].map((_, i) => new Array(string2.length).fill(i));
    
    console.log(JSON.stringify(matrix));
    
    // now we have different references => different objects
    console.log(matrix[0] === matrix[1]) // returns false