HOWTO · JavaScript

JavaScript 中的二维数组

本教程介绍了如何在 JavaScript 中形成二维数组。

本页内容

JavaScript 二维数组是一个元素为行数组的数组。值已知时可使用嵌套字面量;如果行列数或值来自数据,则可使用循环、Array.from() 或 Array.prototype.map() 创建彼此独立的行。使用两个索引读取单元格:grid[rowIndex][columnIndex]。

什么是 JavaScript 二维数组?

JavaScript 没有单独的二维数组类型。网格由数组嵌套而成:外层数组存放各行,每一行则存放其中的单元格。这种结构可用于表示矩阵、游戏棋盘或其他按行列组织的数据。各行的长度可能不同;如果不能确定数组一定是矩形,就应检查每一行的长度。

数组索引从零开始。在 grid[1][2] 中,1 选中第二行,2 选中该行的第三个单元格。创建行与填入单元格是两个不同的步骤:新分配的数组可能含有尚未初始化的槽位,这些槽位与值为 null 的单元格并不相同。

使用嵌套数组字面量创建二维数组

如果网格固定且各个值已知,可以将每一行写成一个内层数组:

const grid = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

console.log(grid[0][1]);

每个内层数组都是独立的一行。表达式 grid[0][1] 选中的值是 2:第一个索引选择行,第二个索引选择该行中的单元格。当完整数据已经准备好时,使用字面量表示法很方便。

使用循环创建二维数组

如果行列数或单元格的值要在运行时确定,可以使用嵌套循环。每次外层循环都分配一个新行,然后为各个单元格赋值:

const rows = 3;
const columns = 3;
const grid = [];

for (let row = 0; row < rows; row++) {
  grid[row] = [];
  for (let column = 0; column < columns; column++) {
    grid[row][column] = row * columns + column + 1;
  }
}

console.log(grid);

外层循环创建三行彼此独立的行。内层循环将每一行填入从 1 到 9 的值。如果单元格需要以默认值开始,可以在内层循环中赋值,例如 grid[row][column] = 0。

对于需要修改的行,避免使用 Array(rows).fill(Array(columns).fill(0)):fill() 会重复填入同一个行引用,因此修改一行后,所有行中对应列的值看起来都会一同改变。应在每次外层循环中创建一个新行。

使用 Array.from() 创建二维数组

Array.from() 可以创建外层数组,并为每个索引创建一个新行。它的映射回调会收到当前索引,因此可以根据行索引和列索引计算每个单元格的值:

const rows = 3;
const columns = 3;
const grid = Array.from({ length: rows }, (_, row) =>
  Array.from({ length: columns }, (_, column) => row * columns + column + 1)
);

console.log(grid);

外层调用创建三行;内层调用则创建每一行并填入三个值。由于每个外层索引都会触发一次内层 Array.from(),所以每一行都是独立数组。若要让每个单元格从 0 开始,可以将 Array.from({ length: columns }, () => 0) 用作内层调用。

使用 Array.prototype.map() 创建二维数组

map() 会将数组中已有的元素转换为一个新数组。先创建包含实际元素的槽位,确保回调对每一行都会运行;单独使用 new Array(rows) 会创建稀疏槽位,而 map() 会跳过这些槽位。

const rows = 3;
const columns = 3;
const grid = Array.from({ length: rows }, (_, row) => row).map(row =>
  Array.from({ length: columns }, (_, column) => row * columns + column + 1)
);

console.log(grid);

这里先由 Array.from() 创建一个包含行索引的序列,再由 Array.prototype.map() 为每个索引创建一个单独分配的行。回调也可以返回填有默认值的行,例如 Array.from({ length: columns }, () => 0)。

初始化和访问二维数组中的值

读取单元格时使用 grid[row][column];更新时通过相同的索引赋值,例如 grid[1][2] = 42。对于三行四列的数组,有效行索引为 0 到 2,有效列索引为 0 到 3。JavaScript 不会强制数组必须是矩形,因此每一行的长度决定了该行包含哪些列索引。

若要用相同的初始值初始化网格,应为每一行索引创建一个新行。例如,Array.from({ length: rows }, () => Array.from({ length: columns }, () => 0)) 会创建彼此独立的行,并将每个单元格设为 0。这与会产生稀疏槽位的 new Array(rows) 不同,也不同于用 fill() 重复同一个内层数组。

值已知时选择字面量;需要明确控制构建过程时使用循环;需要生成行和单元格时使用 Array.from();要转换已有且包含实际元素的序列时使用 Array.prototype.map()。这四种方法都会生成普通的嵌套数组;读取或更新单元格时,都采用先行后列的索引方式。