推送到 2D JS 数组中的子数组时遇到问题

Have trouble doing push to a sub-array in a 2D JS array

假设我制作了一个由整数 9 填充的 5 x 2 矩阵 let arr = Array(5).fill(Array(2).fill(9));

现在我想将整数 8 推入矩阵的第四行,方法是 arr[3].push(8);

我最终得到 [[9,9,8],[9,9,8],[9,9,8],[9,9,8],[9,9,8]]。矩阵中的所有行都已被推入 8。 为什么?

我发现如果我做了下面这样的事情,我就得到了我想要的,但是为什么呢?

arr[3] = [...arr[3]];
arr[3].push(8);

简答:这是因为所有 5 个数组都共享对完全相同数组的引用 即 Array(2).fill(9) => [9,9]

快速解决方案:使用Array.form为每个图层创建一个deep-copy

let arr = Array.from({length: 5}, e => Array(2).fill(9));

或尝试这些答案中的任何其他解决方案 (, , ref 3)

查看下面的工作解决方案(注意控制台中的浅拷贝)

// PROBLEM

// Shallow-copies
let arr1 = Array(5).fill([...Array(2).fill(9)]);
arr1[3].push(8);

// writing to the document
document.write('Shallow -> ', arr1)
// loggin in console
console.log('shallow ',  arr1)


// SOLUTION

// deep-copies
let arr2 = Array.from({length: 5}, e => Array(2).fill(9));
arr2[3].push(8);

// writing to the document
document.write('<br><br> Deep -> ', arr2)
// loggin in console
console.log('deep', arr2)


详细信息:如此处文档中所述(描述here 中的第 5 点)关于 .fill 的第一个参数,即您所在的数组传入即 [9,9]

If the first parameter is an object, each slot in the array will reference that object.

文档中也提到了确切的场景,请参阅此代码片段 here

这表明所有项目基本上都是对同一对象的引用 [也称为 shallow copy],更改一个项目将导致其他所有项目发生相同的变化。

Array.from 解决了这个问题,因为 Array(2).fill(9) 现在将在数组的每个元素上创建一个新数组。详细了解 Array.from here


你最后提到的这个修复是有效的,因为通过使用扩展运算符 [...arr[3]] 我们正在第 4 个索引上创建这个 [9,9] 数组的深层副本,这不是对该数组的引用相同的初始数组 [9,9] 不再如此,现在在第 4 个索引处更改此项目只会更改第 4 个项目的数组本身。

注意这个扩展运算符 ...arr 只创建一个 single level deep copy 所以,如果(假设)这个 arr[3] 包含另一个多级数组,那么只有第一层将被创建为深拷贝,所有内部层将保留为浅拷贝[即对对象的相同引用]