推送到 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]
包含另一个多级数组,那么只有第一层将被创建为深拷贝,所有内部层将保留为浅拷贝[即对对象的相同引用]
假设我制作了一个由整数 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));
或尝试这些答案中的任何其他解决方案 (
查看下面的工作解决方案(注意控制台中的浅拷贝)
// 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]
包含另一个多级数组,那么只有第一层将被创建为深拷贝,所有内部层将保留为浅拷贝[即对对象的相同引用]