多維陣列(Arrays)
簡介
在 JavaScript 中,陣列(Array)是最常用的資料結構之一,幾乎每個前端或後端專案都會與它打交道。當資料不只是一列線性的元素,而是呈現「表格」或「樹狀」的形態時,我們就需要使用多維陣列(Multi‑dimensional Array)來儲存與操作。
多維陣列讓我們可以在同一個變數中,保存二維(矩陣)、三維(立體座標)甚至更高維度的資料,這在 遊戲開發、資料視覺化、矩陣運算 等情境下尤為重要。掌握多維陣列的創建、存取與遍歷技巧,能讓程式碼更具可讀性與可維護性,也為日後學習更進階的演算法奠定基礎。
核心概念
1. 多維陣列的基本結構
在 JavaScript 裡,多維陣列其實是「陣列的陣列」。例如,二維陣列可以寫成:
// 2×3 的二維陣列(2 列、3 行)
const matrix = [
[1, 2, 3], // 第 0 列
[4, 5, 6] // 第 1 列
];
matrix[0][2]取得第 0 列第 2 行的元素,結果為 3。- 取值的順序是「外層陣列 → 內層陣列」,因此先指定列(row),再指定行(column)。
2. 動態產生多維陣列
手寫每一層的陣列在資料量大時不切實際,常會用迴圈或 Array.from 產生:
// 建立 4×5 的二維陣列,預設值為 0
const rows = 4, cols = 5;
const grid = Array.from({ length: rows }, () =>
Array.from({ length: cols }, () => 0)
);
console.log(grid);
技巧:使用
Array.from的第二個參數可以直接寫入初始化函式,讓程式更簡潔。
3. 三維以上的陣列
三維陣列常見於 3D 圖形、棋盤遊戲的立體棋局,結構為「陣列的陣列的陣列」:
// 2×3×4 的三維陣列,值為其索引之和
const depth = 2, rows3D = 3, cols3D = 4;
const cube = Array.from({ length: depth }, (_, d) =>
Array.from({ length: rows3D }, (_, r) =>
Array.from({ length: cols3D }, (_, c) => d + r + c)
)
);
console.log(cube);
4. 常用的遍歷方法
4.1 for 迴圈(最直觀)
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(`matrix[${i}][${j}] = ${matrix[i][j]}`);
}
}
4.2 forEach 結合解構賦值
matrix.forEach((row, i) => {
row.forEach((value, j) => {
console.log(`row ${i}, col ${j}: ${value}`);
});
});
4.3 flat 與 flatMap(將多維展平)
// 將二維陣列展平成一維陣列
const flatArray = matrix.flat(); // [1,2,3,4,5,6]
// 同時展平兩層
const deep = [[[1]], [[2]], [[3]]];
console.log(deep.flat(2)); // [1,2,3]
注意:
flat只在 ES2019 以上支援,舊環境需自行實作或使用 polyfill。
5. 多維陣列的拷貝與深層複製
直接賦值只會產生引用,修改其中一層會影響原始陣列:
const original = [[1, 2], [3, 4]];
const shallowCopy = original; // 兩者指向同一個陣列
shallowCopy[0][0] = 99;
console.log(original[0][0]); // 99
若要深層複製,可以使用 JSON.parse(JSON.stringify(...)) 或遞迴:
// 簡易深層複製(適用於純數值/字串/布林的陣列)
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy[0][0] = 7;
console.log(original[0][0]); // 99(不受影響)
⚠️:JSON 方法無法處理
undefined、function、Symbol等特殊值,若有需求請自行實作遞迴拷貝。
常見陷阱與最佳實踐
| 陷阱 | 可能的結果 | 解決方式 |
|---|---|---|
| 陣列長度不一致(所謂「鋸齒狀」陣列) | 讀取 matrix[i][j] 時出現 undefined,可能導致程式錯誤 |
在建立時統一長度,或在存取前先檢查 Array.isArray(matrix[i]) |
| 引用傳遞 | 修改子陣列會影響其他變數 | 使用深層複製或 map 產生新陣列 |
| 過度巢狀迴圈 | 效能低、可讀性差 | 若維度 > 2,考慮使用 flatten 後一次遍歷,或抽象成 函式(如 forEach2D) |
flat 深度不夠 |
仍留下子陣列 | 明確傳入正確的 depth,或使用 Infinity 完全展平 |
忘記 let / const 在迴圈中使用 var |
變數提升導致意外行為 | 永遠使用 let 或 const,避免作用域混淆 |
最佳實踐
- 明確宣告維度:在程式碼註解或變數命名中說明陣列的維度,例如
const board3D = ... // depth × rows × cols。 - 使用函式封裝遍歷:將常見的二維/三維迭代抽成
forEach2D、forEach3D,提升重用性。 - 避免硬編碼索引:使用
for...of搭配entries()取得索引,減少錯誤。 - 適時展平:若只需要一次性檢查所有元素,
flat(Infinity)可以簡化程式。 - 測試邊界:寫單元測試驗證空陣列、單層陣列、不同長度的子陣列皆能正確處理。
實際應用場景
1. 棋盤遊戲(如井字棋、圍棋)
二維陣列可直接映射棋盤格子,board[row][col] 代表每個格子的狀態(空、黑子、白子)。配合 深層複製,可實作「回溯」或「悔棋」功能。
// 3×3 井字棋板,0 = 空,1 = X,2 = O
let ticTacToe = Array.from({ length: 3 }, () => Array(3).fill(0));
function place(row, col, player) {
if (ticTacToe[row][col] !== 0) return false; // 已佔用
ticTacToe[row][col] = player;
return true;
}
2. 圖像處理(像素矩陣)
每個像素的 RGB 值可用三維陣列表示:image[y][x][channel](channel = 0~2)。透過遍歷,可快速執行濾鏡、亮度調整等運算。
function invertColors(image) {
image.forEach(row => {
row.forEach(pixel => {
// 255 - 原值 = 反相顏色
pixel[0] = 255 - pixel[0]; // R
pixel[1] = 255 - pixel[1]; // G
pixel[2] = 255 - pixel[2]; // B
});
});
}
3. 三維座標系統(遊戲、模擬)
在 3D 遊戲中,常用 三維陣列 來保存地圖格子或體素(voxel)資訊,例如 world[depth][row][col] 表示特定高度的地形類型。
// 建立 10×10×10 的體素世界,預設為空氣 (0)
const world = Array.from({ length: 10 }, () =>
Array.from({ length: 10 }, () => Array(10).fill(0))
);
// 放置一個方塊
function setBlock(z, y, x, type) {
world[z][y][x] = type;
}
4. 數據分析(矩陣運算)
在統計或機器學習前端實作時,常需要 矩陣相乘、轉置 等操作。多維陣列提供了直觀的資料結構。
// 簡易矩陣相乘(2×3 * 3×2)
function multiply(A, B) {
const rowsA = A.length, colsA = A[0].length;
const colsB = B[0].length;
const result = Array.from({ length: rowsA }, () => Array(colsB).fill(0));
for (let i = 0; i < rowsA; i++) {
for (let k = 0; k < colsA; k++) {
for (let j = 0; j < colsB; j++) {
result[i][j] += A[i][k] * B[k][j];
}
}
}
return result;
}
總結
多維陣列是 JavaScript 中強而有力的資料容器,從簡單的二維表格到複雜的三維座標,都能以「陣列的陣列」方式直觀表達。掌握以下要點,能讓你在開發中更加得心應手:
- 建立方式:使用巢狀
Array.from或迴圈動態產生,避免手寫大量硬編碼。 - 存取與遍歷:熟悉
for、forEach、flat等方法,根據需求選擇最適合的遍歷策略。 - 深層拷貝:了解引用與拷貝的差異,必要時使用深層複製避免副作用。
- 最佳實踐:統一維度、封裝遍歷、避免過深巢狀迴圈,並在關鍵位置加入單元測試。
透過本篇的概念說明與實務範例,你已具備在 遊戲開發、圖像處理、資料分析 等領域使用多維陣列的基礎。未來若需要更高階的矩陣運算,亦可結合 TypedArray、WebGL 或第三方數學函式庫(如 mathjs)進一步提升效能與功能。祝你在 JavaScript 的陣列世界裡玩得開心、寫得順手!