为什么我无法在JS中复制这个二维数组?如何进行复制?

3
我正在实现约翰·康威的生命游戏,但是我遇到了一个奇怪的问题。以下是引起问题的代码的简短版本:
let lifeMap = [
  [true, false, false],
  [false, false, false],
  [false, false, false]
];
let oldLifeMap = lifeMap.slice();
for (let row = 0; row < lifeMap.length; row++) {
  for (let val = 0; val < lifeMap[row].length; val++) {
    let bool = lifeMap[row][val];
    let newBool = false; // here is where I would determine if cell is alive/dead
    lifeMap[row][val] = newBool;
    if (row === 0 && val === 0) console.log("at (0,0)", oldLifeMap[0][0]);
  }
}

作为对此代码的回应,JavaScript会打印出 at (0,0) false。我需要它在下一代开始之前保持为true
我认为执行 let oldLifeMap = lifeMap.slice() 可以解决这个问题,但事实并非如此,而且我不确定原因。(难道它不应该将二维数组复制并创建第二个引用吗?)
无论如何,这里发生了什么情况,我该如何成功地创建 lifeMap 的一个真正副本呢?

外部数组是一个副本,但每个内部数组仍然是一个引用。这是你所做的预期行为。 - Patrick Roberts
3
.map(a => a.slice()) - Patrick Roberts
我会尝试这个 https://dev59.com/aWYr5IYBdhLWcg3wVY3J - Andrew Horn
是的,我认为这是最好的方法(也是我要写的)。这里有一个演示 - Andy
1
var copy = JSON.parse(JSON.stringify(lifeMap)) - epascarello
显示剩余6条评论
2个回答

12

@Redu的答案致敬,他的答案适用于N维数组,但在特定于2D数组的情况下是不必要的。为了深层克隆你的特定2D数组,你只需要:

let oldLifeMap = lifeMap.map(inner => inner.slice())

这将使用 .slice() (没有参数)创建每个内部数组的副本,并将其存储到使用 .map() 创建的外部数组的副本中。


5
您可以按照以下方式克隆一个ND(深度嵌套)数组:
Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

或者,如果您不想修改Array.prototype,您可以简单地重构上面的代码,例如:

function cloneArray(a){
  return a.map(e => Array.isArray(e) ? cloneArray(e) : e);
};

有趣的提议,但在我看来对于一个不需要递归函数的二维数组来说太过于泛泛了。 - Patrick Roberts
1
@Patrick Roberts 上面的 Array.prototype 扩展只是为了说明算法的思路。当然,它必须通过 Object.defineProperty() 来完成。并且同意最好将其实现为静态的 Array.clone() - Redu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接