0

Please, try to understand where is a mistake.

I have an array table and two functions appendRow and appendCol.

If I execute appendCol first it works correct and in each of array in table 'y' element is appended.

But, If I execute first 'appendRow', and then appendCol 'y' is added twice two first and last array in table.

I do not understand why.

My code is bellow:

var table = [
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x']
]

var appendRow = () => {
  var newTable = table;
  newTable.push(newTable[0])
  table = newTable

  console.log(table)
}

var appendCol = () => {
  var newTable = table;
  newTable.forEach((element) => {
    element.push("y")
  })
  table = newTable;
  console.log(table);
}

appendRow();
appendCol();

Link to jsfiddle

You can see console after executing.

Try to comment first function and second works correct

Erazihel
  • 7,295
  • 6
  • 30
  • 53
a.kozubenko
  • 1,030
  • 3
  • 15
  • 24
  • You need to read [Is JavaScript a pass-by-reference or pass-by-value language?](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language). Your allocation of objects is very confusing in `appendRow` – Liam Jul 10 '17 at 12:51

2 Answers2

3

When you run newTable.push(newTable[0]) you're not pushing a copy of the first sub-array, you're pushing a reference to that sub-array, so now newTable contains two separate references to that sub-array, meaning you'll iterate over it twice and subsequently push "y" to it twice.

In order to resolve this you can make sure you actually copy the sub-array in appendRow() instead of just referencing it:

newTable.push(newTable[0].slice())

The slice() method without any arguments will return a copy of the array.

On another note, because arrays (and other object types) are referenced, your reassigning between newTable and table doesn't really accomplish anything.

Lennholm
  • 7,205
  • 1
  • 21
  • 30
3

In the appendRow function you're pushing a reference to the first row into the last row, not a clone/copy. So when you loop over the rows in your appendCol function, the first row gets values appended twice because it's there twice - as the first row, and a reference to it as the last row.

You can create a clone of the row by using the slice() function. I've also simplified all the table/newTable stuff which is entirely unnecessary (again because it creates references and not clones), and stringified the console logs for easier reading:

var table = [
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x'],
  ['x', 'x', 'x', 'x']
]

console.log(JSON.stringify(table));

var appendRow = () => {
  table.push(table[0].slice());
  console.log(JSON.stringify(table));
}

var appendCol = () => {
  table.forEach((element, index, array) => {
    element.push("y");
  });
  console.log(JSON.stringify(table));
}

appendRow();
appendCol();

Here it is updated in JSFiddle, too: https://jsfiddle.net/gy97p92d/4/

ADyson
  • 57,178
  • 14
  • 51
  • 63