如何在JavaScript中创建二维数组?

1386

我在网上看到一些地方说JavaScript不能声明二维数组,有些则给出了一个例子并称可以,还有其他人驳斥这个例子等等。

  1. 如何在JavaScript中声明一个二维数组?(假设它是可能的)

  2. 如何访问它的成员?(myArray[0][1] 还是 myArray[0,1]?)


26
假设采用一种有些学究的定义,使用 JavaScript 技术实际上无法创建二维数组。但是,您可以创建一个数组的数组,这等同于同样的效果。 - I. J. Kennedy
22
FYI... 当你使用var arr2D = new Array(5).fill(new Array(3));将一个数组填充了更多的数组时,Array(5) 的每个元素都会指向同一个Array(3)。因此最好使用for循环动态地填充子数组。 - Josh Stribling
91
a = Array(5).fill(0).map(x => Array(10).fill(0)) - Longfei Wu
5
换句话说,fill 函数不会为要填充的数组的每个索引调用 new Array(3),因为它不是 Lambda 表达式或任何其他东西,比如 Longfei Wu 在上面的评论中,它最初使用 0 填充数组,然后使用 map 函数和 Lambda 来填充每个元素为新数组。fill 函数只是简单地根据你告诉它的内容来填充数组。这讲得通吗?有关 map 函数的更多信息,请参见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map - Josh Stribling
2
@kalehmann没问题:https://meta.stackoverflow.com/a/252017/2311074 如果新问题更好或有更好的答案,则将旧问题标记为新问题的重复。 - Adam
显示剩余7条评论
55个回答

5

Javascript不支持二维数组,但是我们可以将一个数组存储在另一个数组中,并根据需要访问那个数组中的数据。请记住,数组编号从开始。

代码示例:

/* Two dimensional array that's 5 x 5 

       C0 C1 C2 C3 C4 
    R0[1][1][1][1][1] 
    R1[1][1][1][1][1] 
    R2[1][1][1][1][1] 
    R3[1][1][1][1][1] 
    R4[1][1][1][1][1] 
*/

var row0 = [1,1,1,1,1],
    row1 = [1,1,1,1,1],
    row2 = [1,1,1,1,1],
    row3 = [1,1,1,1,1],
    row4 = [1,1,1,1,1];

var table = [row0,row1,row2,row3,row4];
console.log(table[0][0]); // Get the first item in the array

5

一行代码创建一个m*n的二维数组,其中所有元素都为0。

new Array(m).fill(new Array(n).fill(0));

3
实际上,这将只创建两个数组。第二维将在每个索引中是相同的数组。 - Pijusn
7
是的,我确认了 gotcha。快速修复:a = Array(m).fill(0).map(() => Array(n).fill(0))map 将解开引用并为每个插槽创建唯一的数组。 - dmitry_romanov

5

我找到了一个快速制作二维数组的方法。

function createArray(x, y) {
    return Array.apply(null, Array(x)).map(e => Array(y));
}

您可以轻松地将此函数转换为ES5函数。

function createArray(x, y) {
    return Array.apply(null, Array(x)).map(function(e) {
        return Array(y);
    });
}

为什么这有效:使用new Array(n)构造函数创建一个原型为Array.prototype的对象,然后将对象的length分配给它,从而得到一个未填充的数组。由于它没有实际成员,我们无法运行Array.prototype.map函数。
但是,当您向构造函数提供多个参数时,例如Array(1, 2, 3, 4),构造函数将使用arguments对象来正确实例化和填充Array对象。
因此,我们可以使用Array.apply(null, Array(x)),因为apply函数会将参数展开到构造函数中。为了澄清,使用Array.apply(null, Array(3))等同于使用Array(null, null, null)
现在,我们已经创建了一个实际填充的数组,我们只需要调用map并创建第二层(y)。

3
我发现以下代码适合我的需求:
var map = [
    []
];

mapWidth = 50;
mapHeight = 50;
fillEmptyMap(map, mapWidth, mapHeight);

...

function fillEmptyMap(array, width, height) {
    for (var x = 0; x < width; x++) {
        array[x] = [];
        for (var y = 0; y < height; y++) {

            array[x][y] = [0];
        }
    }
}

3
你可以分配一个行数组,其中每一行都是相同长度的数组。或者你可以分配一个有rows*columns个元素的一维数组,并定义方法将行/列坐标映射到元素索引。
无论你选择哪种实现方式,如果将其封装在对象中,则可以在原型中定义访问器方法,使API易于使用。

3

请使用全局对象Array,将项目填充到数组中:

let arr = new Array(5).fill([]);

或者如果已知长度的二维数组:

let arr = new Array(5).fill(new Array(2));

第二个代码有问题!因为它在第一个数组的每个索引处创建了Array(2)的浅拷贝。所以如果你设置arr[0][0] = 1,那么它也会将arr[1][0]、arr[2][0]、arr[3][0]等等修改为1。 - Riyad Zaigirdar

3
一个简化的例子:
var blocks = [];

blocks[0] = [];

blocks[0][0] = 7;

3

我不是很喜欢使用.fill()的ES6解决方案。虽然有些方法可以工作,但为了避免引用复制问题而采取的额外步骤使它们不直观。

我建议的ES6方法是充分利用扩展操作符,对外部和内部数组都要使用。我认为这种方法更易于理解。

[...Array(3)].map(() => [...Array(4)])

如果需要设置初始值,则在内部数组创建上链接 .map()

[...Array(3)].map(() => [...Array(4)].map(() => 0))

最后,一个类型安全的 TypeScript 工具函数:
export const createMultiDimensionalArray = <T>(
  n: number,
  m: number,
  initialVal?: T,
): T[][] => {
  const matrix = [...Array(n)].map(() => [...Array(m)]);
  return initialVal === undefined
    ? matrix
    : matrix.map(r => r.map(() => initialVal));
};

以下是使用IT技术的示例:

const a = createMultiDimensionalArray(1, 2);
a[1][2] = 3;     // Works

const b = createMultiDimensionalArray(2, 3, false);
b[1][2] = true;  // Works
b[1][2] = 3;     // Error: Type '3' is not assignable to type 'boolean'.

2

创建多维数组的递归函数:

var makeArray = function (dims, arr) {          
    if (dims[1] === undefined) {
        return new Array(dims[0]);
    }

    arr = new Array(dims[0]);

    for (var i=0; i<dims[0]; i++) {
        arr[i] = new Array(dims[1]);
        arr[i] = makeArray(dims.slice(1), arr[i]);
    }

    return arr;
}

构建一个2x3x4x2的四维数组:
var array = makeArray([2, 3, 4, 2]);    

2
const arr = new Array(5).fill(new Array(5).fill(0));
console.log(arr);

8
由于这个答案显示为第一个结果,我想提一下(就像其他人已经提到的),在这个解决方案中,第二维数组是通过引用复制的,因此这可能不是创建二维数组的最佳方法。 - air5
@air5 你似乎没有意识到排序顺序是不可预测的。这里没有所谓的“第一”。排序顺序是可以单独配置的。 - Yunnosch
1
这实际上一开始让我很困惑。因为它是通过引用用第一个数组填充第二个维度,所以对任何数组所做的任何更改都会影响到第二个维度中的所有数组。 - jfunk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接