为什么数组副本在更改真实数组后会发生更改



我正在编程国际象棋引擎,以便在未来看到我必须更改棋盘配置并删除更改的部件。简而言之,这个有很多问题

function chessAi(){
let copy=[...board]
pisces.forEach(pisce=>{
pisce.forEach(move=>{
//play move on the board
//reset board to original board
board=copy
}
}
}

这根本不起作用,我也不知道为什么,但我搞砸了,发现如果我像这个一样定义每次移动的副本

function chessAi(){
pisces.forEach(pisce=>{
pisce.forEach(move=>{
let copy=[...board]
//play move on the board
//reset board to original board
board=copy
}
}
}

它非常有效,有人能解释为什么以及如何解决吗?这需要大量的处理能力,并使计算动作更加困难。提前感谢

pisce.forEach的第一次迭代后,copyboard将引用相同的数组。正如@vcodepro所提到的,一种方法是通过克隆副本来恢复电路板。另一种选择是在每次迭代开始时克隆它,并在处理完成后将其丢弃:

function chessAi(){
let selectedConfig = null
pisces.forEach(pisce=>{
pisce.forEach(move=>{
newConfig = [...board]
//play move on the newConfig
//if the newConfig is appropriate
selectedConfig = newConfig
}
}
return selectedConfig
}

通过这种方式,您可以确保板的当前状态不受任何修改的影响。否则,如果你想在其他地方使用board,并且在这里进行了修改,可能会导致很难找到错误。

如果数据未嵌套,则排列运算符会生成数据的深度副本

这意味着当您在数组中嵌套数据时,排列运算符将创建最顶部数据的深层副本和嵌套数据的浅层副本。这就是当实际数组发生变化时它会发生变化的原因。

让我用一个例子来解释

// Original Array
let board = ['board1', 'board2',['board3','board4']];
// On copy this board data to a new variable via spread operator.
let copy = [...board];
// It looks like we get a deep copy of whole board array but in fact we don’t.
console.log(copy[0]) // 'board1'
console.log(copy[2][1]) // 'board4'

现在,如果我们更改保存在index 2的数组,copy[2][1]不仅会更改我们的变量"的数据;板;但是";复制";也因此,这意味着board[2][1]指向与copy[2][1]在内存中指向的阵列相同的阵列。

这就是第二个解决方案在每次迭代后对每个嵌套数组进行深度复制时起作用的原因。

在第一个代码片段的第一次迭代中,您创建了board数组的克隆(副本(,但在第一次迭代之后以及在接下来的迭代中,我们使用的是在第一次循环中创建的同一个数组,这就是为什么您会得到意外的结果。

但在第二个代码片段中,您将在每次迭代中创建board数组的新克隆(副本(。

问题的解决方案可以使用copy变量的克隆(副本(重置board变量:

function chessAi(){
let copy=[...board]
pisces.forEach(pisce=>{
pisce.forEach(move=>{
//play move on the board
//reset board to original board
board=[...copy]
}
}
}