【问题标题】:Cloned my array, and yet the original array keeps getting modified. Why?克隆了我的阵列,但原始阵列不断被修改。为什么?
【发布时间】:2020-02-29 07:16:57
【问题描述】:
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 ] ]

我已经使用 slice() 克隆了我的数组,在 //Horizo​​ntal 下访问它而不是原始数组,但是当我返回原始数组时,它仍然被修改。我究竟做错了什么?我已经尝试了各种方法来创建数组的克隆,尽管从未访问过它,但它们都以某种方式修改了原始数组。

【问题讨论】:

  • 搜索:"[javascript] array shallow clone"。有 许多 个重复项。
  • stackoverflow.com/a/597726/2864740 的第一段看起来很简洁(数组也是对象)。
  • 在数字数组中,使用.slice() 将生成一个新数组,无论如何修改,都不会影响原始数组。但是您有一个 数组 数组。具体来说,数组的引用数组。您确实复制了数组,但新数组与旧数组具有相同的引用 - 指向相同的数据。他们仍然指向相同的数据。如果您希望它们不发生变化,您将需要对所有内部数组的新副本的新引用。

标签: javascript


【解决方案1】:

这是因为.slice() 只执行了浅拷贝,因此一些值仍然从原始数组中引用。请在此问题的答案中查看更详细的解释:What is the difference between a shallow copy and a deep copy with JavaScript arrays?

【讨论】:

    【解决方案2】:

    Array.prototype.slice() 进行浅层克隆。这意味着如果数组包含对象,则克隆将引用同一个对象。

    board 是一个二维数组。该数组中的每个元素都是一个数组。 board.slice() 提供了board 的浅拷贝。如果您执行newBoard[0] = .... 之类的操作,则原始board 不会改变。但是newBoard 中的每个元素,例如newBoard[0] 仍然指的是与之前board[0] 相同的对象。 newBoard[0][0] = ... 形式的任何更改也将更新 board[0][0]

    为了解决这个问题,您需要进行深度克隆。已经有图书馆在执行此操作。但如果你的用例只是二维数组,你可以这样做:

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

    【讨论】:

      【解决方案3】:
      let newBoard = JSON.parse(JSON.stringify(board));
      

      这成功了。我认为它与浅拷贝有关,但如果不能单独修改它,我不确定创建同一个数组的副本有什么意义?

      【讨论】:

      • 也许举个例子会有所帮助:如果每个学生数组都包含相同的教师数据,您可能只想更新教师数据一次。从另一个学生数组创建一个新的学生数组,可以在不破坏教师链接的情况下实现这一点。您的问题使用维度一致的多维数组,例如矩阵;但是,情况并非总是如此。数组可以有一些元素是字符串、数字和其他维度或类型不一致的对象/数组。如果您编辑了其中一个非对象元素,它将是可变的。
      • 可以单独修改。您可以设置newBoard[0] = someNewData 而无需修改board。这就是浅拷贝的含义。但是由于原始和副本都包含对相同数组的引用,这些数组尚未被克隆(所有内部数组),访问这些引用并修改它们的数据仍然会修改它两者兼得。
      • 嗯,有道理。谢谢!
      猜你喜欢
      • 2019-12-05
      • 1970-01-01
      • 2011-09-08
      • 2013-06-12
      • 1970-01-01
      • 2013-03-27
      • 2020-05-21
      • 2016-09-08
      • 1970-01-01
      相关资源
      最近更新 更多