使用Array.fill()初始化一个二维数组的小坑

Sun, July 21, 2024 - 3 min read

为什么使用两个new Array嵌套不行?

假设我们要创建一个 4*6 的二维数组,里面填满0,使用两个new Array嵌套可以写成:

const arr = new Array(4).fill(new Array(6).fill(false))  

此时二维数组已经创建好了,看起来是不是挺好的?

图片1

但是当我们修改第二行二列时,会变成这样:

arr[1][1] = true

图片2

这是因为arr的所有子数组实际上都是对同一个数组的引用。这意味着对任何一个子数组的修改都会影响其他所有子数组。

在MDN是这么描述Array原型上的fill()方法的

fill(value)
fill(value, start)
fill(value, start, end)

value

用来填充数组元素的值。注意所有数组中的元素都将是这个确定的值:如果 value 是个对象,那么数组的每一项都会引用这个元素。

参考文档

方法1

使用new Array结合map初始化一个m*n的二维数组。

const arr = new Array(m).fill(0).map(_ => new Array(n).fill(0))

这种方法首先创建一个长度为 m 的数组,然后使用 map 函数为每个元素创建一个新的长度为 n 的数组,每个元素都初始化为0。这种方法的好处是每个子数组都是独立的,即它们是新创建的数组,而不是引用同一个数组。

方法2

使用Array.form来初始化一个m*n的二维数组。

const arr = Array.from({length: m}, e => Array(n).fill(0))
  1. Array.from() 函数:这个函数用于从一个类数组对象或可迭代对象创建一个新的数组实例。它接受两个参数:第一个参数是要转换为数组的对象,第二个参数是一个映射函数,用于对每个元素进行处理。

  2. {length: m}:这是一个对象,它有一个 length 属性,其值是 m。这个对象本身不是数组,但它具有一个 length 属性,这使得 Array.from 可以将其转换为一个长度为 m 的数组。

  3. e => Array(n).fill(0):这是传递给 Array.from 的映射函数。它对于 Array.from 创建的每个元素(在这个例子中,每个元素都是 undefined,因为 {length: m} 对象没有具体的元素值),都创建了一个新的长度为 n 的数组,并将所有元素初始化为 0。