forEach工作不正确,有助于理解原因

时间:2017-07-10 12:43:38

标签: javascript arrays

请尝试了解哪里出错。

我有一个数组table和两个函数appendRowappendCol

如果我首先执行appendCol它的工作正确,并且在表'y'中的每个数组中都附加了元素。

但是,如果我先执行'appendRow',然后appendCol'y'将两次加到表中的第一个和最后一个数组。

我不明白为什么。

我的代码如下:

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();

链接到jsfiddle

执行后你可以看到控制台。

尝试评论第一个功能,第二个工作正确

2 个答案:

答案 0 :(得分:3)

当您运行newTable.push(newTable[0])时,您没有推送第一个子数组的副本,而是推送对该子数组的引用,所以现在newTable包含对该子数组的两个单独引用子数组,意味着你将迭代两次,然后将"y"推送到它两次。

为了解决此问题,您可以确保在appendRow()中实际复制子数组,而不仅仅是引用它:

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

不带任何参数的slice()方法将返回数组的副本。

另一方面,由于引用了数组(和其他对象类型),因此在newTabletable之间重新分配并没有真正完成任何事情。

答案 1 :(得分:3)

在appendRow函数中,您将引用推送到最后一行的第一行,而不是克隆/副本。因此,当你遍历appendCol函数中的行时,第一行会获得两次附加的值,因为它有两次 - 作为第一行,并且引用它作为最后一行。

您可以使用slice()函数创建行的克隆。我还简化了所有table / newTable内容,这些内容完全没有必要(同样是因为它创建引用而不是克隆),并将控制台日志字符串化以便于阅读:



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();




此处它也在JSFiddle中更新:https://jsfiddle.net/gy97p92d/4/