JavaScript 陣列解構(Array Destructuring)
簡介
在日常的前端開發中,我們經常需要從陣列中取出特定的元素,或把多個變數一次性賦值。傳統的做法往往需要寫許多 let、var 或索引存取的程式碼,既冗長又容易出錯。ES6 引入的 陣列解構(Array Destructuring)讓這類操作變得簡潔直觀,只要一行語法就能同時完成多個變數的解構、預設值、剩餘元素的收集等功能。
掌握陣列解構不僅能提升程式碼可讀性,還能減少不必要的臨時變數,對於 函式參數的處理、資料轉換、以及與其他語法(如展開運算子、迭代器)結合 都有相當大的幫助。因此在本單元,我們將深入探討陣列解構的核心概念、常見陷阱與最佳實踐,並透過實務範例說明它在真實專案中的應用方式。
核心概念
1. 基本語法
陣列解構的語法形式是把左側的變數以陣列的形狀寫出,右側則是要解構的來源陣列:
const [a, b] = [1, 2]; // a = 1, b = 2
- 左側的
[]表示「我想要從陣列中取出」的結構。 - 右側的
[]是實際的來源資料。 - 位置對應:第一個變數對應第一個元素,依此類推。
小技巧:如果不需要某個位置的元素,只要留空或使用逗號跳過即可。
const [first, , third] = [10, 20, 30]; // first = 10, third = 30
2. 預設值(Default Value)
當來源陣列的某個位置是 undefined,解構的變數會取得 預設值:
const [x = 5, y = 10] = [undefined, 20];
console.log(x); // 5
console.log(y); // 20
注意:只有在來源為
undefined時才會套用預設值,null、0、''等仍保留原值。
3. 剩餘元素(Rest Element)
使用展開運算子 ... 可以一次取得「剩餘」的所有元素,類似於 Array.prototype.slice:
const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
...必須放在左側陣列的 最後一個位置,否則會拋出語法錯誤。
4. 嵌套解構(Nested Destructuring)
解構不只支援一層,對於多維陣列同樣適用:
const [[a, b], [c, d]] = [[1, 2], [3, 4]];
console.log(a, b, c, d); // 1 2 3 4
結合預設值與剩餘元素也可以:
const [first, [second = 0, ...rest] = []] = [10, [20, 30, 40]];
console.log(first); // 10
console.log(second); // 20
console.log(rest); // [30, 40]
5. 在函式參數中的解構
函式的參數列表同樣支援解構,讓呼叫端只需要傳入陣列即可:
function sum([a, b, c]) {
return a + b + c;
}
console.log(sum([1, 2, 3])); // 6
如果參數有預設值或剩餘元素:
function logger([msg, level = 'info', ...extra]) {
console.log(`[${level}] ${msg}`, ...extra);
}
logger(['系統啟動', undefined, { user: 'Alice' }]);
// [info] 系統啟動 { user: 'Alice' }
程式碼範例
範例 1:快速交換兩個變數的值
傳統寫法需要暫存變數,而解構只要一行:
let a = 5, b = 9;
[a, b] = [b, a];
console.log(a, b); // 9 5
為什麼好? 省去臨時變數,避免因忘記宣告而產生的 bug。
範例 2:從 API 回傳的陣列中挑選需要的欄位
假設後端回傳 [id, name, email, role],我們只關心 name 與 email:
function getUserInfo([, name, email]) {
return { name, email };
}
const apiResult = [101, '王小明', 'xiaoming@example.com', 'admin'];
console.log(getUserInfo(apiResult));
// { name: '王小明', email: 'xiaoming@example.com' }
範例 3:結合 map 與解構一次取出多個欄位
const products = [
[101, '筆記型電腦', 1200],
[102, '滑鼠', 35],
[103, '鍵盤', 80]
];
// 只要取得商品名稱與價格
const simpleList = products.map(([ , name, price]) => ({ name, price }));
console.log(simpleList);
// [{name:'筆記型電腦',price:1200},{name:'滑鼠',price:35},{name:'鍵盤',price:80}]
範例 4:使用剩餘元素收集不確定長度的參數
function concatenate([first, ...rest]) {
return rest.reduce((acc, cur) => acc + cur, first);
}
console.log(concatenate(['A', 'B', 'C', 'D'])); // "ABCD"
範例 5:解構與預設值防止 undefined 錯誤
function createPoint([x = 0, y = 0] = []) {
return { x, y };
}
console.log(createPoint([5])); // { x:5, y:0 }
console.log(createPoint(undefined)); // { x:0, y:0 }
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方法 |
|---|---|---|
| 左側變數比來源多 | 多出的變數會被賦值為 undefined,若未處理可能導致後續錯誤。 |
使用預設值或在解構前先檢查陣列長度。 |
| 左側變數比來源少 | 多餘的來源元素會被忽略,這在大多數情況是預期行為。 | 若需要全部元素,記得使用 剩餘元素 (...rest)。 |
| 解構嵌套時忘記預設值 | 深層的 undefined 會導致「Cannot read property of undefined」錯誤。 |
為每層提供預設值,例如 [[a] = []] = arr。 |
| 在函式參數解構時忘記提供預設參數 | 呼叫時傳入 undefined 會拋錯。 |
為參數本身加上預設值:function f([a, b] = []) {}。 |
使用 ... 於非最後位置 |
語法錯誤。 | 確保 ...rest 只出現在左側最後一個位置。 |
最佳實踐
- 保持左側結構與資料來源的可讀性:不要一次寫太多層嵌套,必要時可先拆解成小步驟。
- 配合
const使用:若變數不會再被重新賦值,使用const可以防止意外改寫。 - 結合其他 ES6 語法:如
for...of、Array.prototype.entries(),可讓迭代與解構同時完成。 - 在大型資料轉換時,先做型別檢查:利用
Array.isArray或typeof讓解構更安全。
實際應用場景
1. 前端 UI 狀態管理
在 React、Vue 或 Svelte 等框架中,常需要從 props、state 或 store 中抽取特定值:
// React 範例
const MyComponent = ({ data: [title, description, ...tags] }) => (
<div>
<h1>{title}</h1>
<p>{description}</p>
<ul>{tags.map(tag => <li key={tag}>{tag}</li>)}</ul>
</div>
);
2. 處理 CSV / TSV 資料
讀取檔案後每行會得到字串陣列,利用解構直接取得欄位:
const lines = csvText.split('\n');
const header = lines.shift().split(',');
const records = lines.map(line => {
const [id, name, age] = line.split(',');
return { id, name, age: Number(age) };
});
3. API 回傳多元資料的快速抽取
如 GraphQL 或 REST 回傳的多層陣列,解構可讓代碼保持簡潔:
async function fetchDashboard() {
const response = await fetch('/api/dashboard');
const [summary, recentOrders, stats] = await response.json();
// summary, recentOrders, stats 直接可用
}
4. 測試資料產生(Test Fixtures)
在單元測試中常需要產生多組測試值,解構配合陣列生成器非常便利:
const cases = [
[1, 2, 3],
[0, -1, -1],
[5, 5, 10]
];
cases.forEach(([a, b, expected]) => {
test(`add(${a}, ${b}) === ${expected}`, () => {
expect(add(a, b)).toBe(expected);
});
});
總結
陣列解構是 ES6 為 JavaScript 帶來的強大語法糖,讓我們在處理陣列資料時能以 宣告式、直觀 的方式一次完成多個變數的賦值、預設值、剩餘元素的收集以及深層嵌套的取值。透過本文的概念說明與實務範例,你應該已掌握:
- 基本的
[a, b] = arr語法與跳過元素的技巧。 - 預設值與剩餘元素的使用情境。
- 嵌套解構與在函式參數中的應用。
- 常見的錯誤陷阱以及避免方式。
- 在 UI 開發、資料轉換、API 處理與測試等領域的實際案例。
在寫程式時,善用解構 不僅能減少冗長代碼,還能提升可讀性與維護性。未來遇到需要從陣列或類似結構中抽取資訊的情境,請先考慮使用解構,讓你的程式碼更簡潔、更安全。祝你在 JavaScript 的旅程中玩得開心、寫得順手!