JavaScript 初學者必懂:剩餘參數(Rest Parameters) 與展開參數(Spread Arguments)完整解析!
更新日期: 2025 年 3 月 31 日
本文為 JS 神奇 點點點 系列文:
在 JavaScript 中,你可能會常常看到三個點的語法 ...
,它有兩種超常見的用途:
- 出現在函式定義時,叫做 Rest Parameters(剩餘參數)
- 出現在函式呼叫或資料結構中,叫做 Spread Operator(展開運算子)
這篇文章會帶你認識其中一個重要應用場景:「函式參數中的 Rest 與 Spread 應用」,也就是你常看到的:
function fn(...args) {}
fn(...arr);
雖然語法長得一樣,但意圖和功能完全不同,我們會用清楚的分類與範例,帶你一次搞懂!
Rest Parameters(剩餘參數)是什麼?
定義與用途說明
Rest Parameters 是 JavaScript 函式定義的一種語法,它允許你定義一個「可以接收不定數量參數」的函式。
這在你不知道函式呼叫時會傳進幾個參數的時候,非常有用。
function example(...args) {
console.log(args);
}
...args
就是一個「剩餘參數」。- JavaScript 會把所有多出來的參數自動收集成一個「陣列」,變成
args
。 - 它只會出現在 函式定義的參數部分,而且只能放在參數列表的最後一位。
範例 1:計算總和(sum 函式)
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // ➜ 6
console.log(sum(10, 20, 30, 40)); // ➜ 100
✅ 說明:
...numbers
是 Rest Parameter,用來收集呼叫時傳進來的所有參數。- 不管你傳幾個數字進去,它都會自動幫你收成一個陣列。
sum(1, 2, 3)
→numbers = [1, 2, 3]
sum(10, 20, 30, 40)
→numbers = [10, 20, 30, 40]
reduce()
方法就是用來把陣列裡的所有數字「加總」起來。
這讓你可以寫出非常彈性、可擴展的工具函式,而不用事先定義 a, b, c, d...
一堆參數。
範例 2:日誌工具 logAll(多參數列印)
function logAll(...messages) {
messages.forEach(msg => console.log('[LOG]', msg));
}
logAll('啟動中', '載入資料', '完成');
// [LOG] 啟動中
// [LOG] 載入資料
// [LOG] 完成
✅ 說明:
...messages
會把所有傳進來的參數組成陣列。forEach()
可讓你依序處理每個訊息。- 這種設計在建立自己的 logger、debug 工具、API log 等場景非常常見!
⚠️ 注意:
- Rest Parameters 只能放在最後一個參數:
function wrong(...args, other) {} // ❌ 會報錯
- 可以與其他固定參數搭配:
function tagLog(prefix, ...msgs) {
msgs.forEach(msg => console.log(prefix, msg));
}
tagLog('[INFO]', '載入中', '成功');
// [INFO] 載入中
// [INFO] 成功
Spread Arguments(展開參數)是什麼?
定義與用途說明
Spread Arguments 是指你在「呼叫函式」的時候,使用展開運算子(...
)把一個陣列或類陣列結構「打散」成一組組獨立的參數,傳進函式中。
const data = [1, 2, 3];
fn(...data);
- 這會等效於
fn(1, 2, 3)
- 適用於你已經有一個陣列,但函式預期的是「多個獨立參數」時
範例 1:傳陣列進函式中(greet)
function greet(name1, name2, name3) {
console.log(`Hello ${name1}, ${name2}, and ${name3}`);
}
const names = ['Alice', 'Bob', 'Charlie'];
greet(...names);
// Hello Alice, Bob, and Charlie
✅ 說明:
...names
把['Alice', 'Bob', 'Charlie']
展開成'Alice', 'Bob', 'Charlie'
- 相當於直接寫:
greet('Alice', 'Bob', 'Charlie')
- 非常實用,尤其當你取得的參數是從陣列來源(例如 API 回傳、使用者輸入)
範例 2:搭配 Math 函式使用
const numbers = [10, 20, 5, 99, 2];
const max = Math.max(...numbers);
console.log(max); // ➜ 99
✅ 說明:
Math.max()
接受多個數字參數,但不能直接傳一個陣列- 使用
...
展開陣列就能正確取得最大值
Rest 與 Spread 的對照與記憶
名稱 | 功能 | 出現位置 | 關鍵概念 |
---|---|---|---|
Rest Parameter | 收集參數(打包成陣列) | 函式定義 | 多個參數 → 陣列 |
Spread Arguments | 展開陣列內容為參數 | 函式呼叫 | 陣列 → 多個參數 |
🧠 記憶口訣:Rest 是打包,Spread 是打開。看位置判斷就不會混!
✅ 小結:你什麼時候會用這兩種語法?
Rest Parameters 適合:
- 建立接受不定參數數量的函式
- 撰寫彈性工具函式(像 sum, logger)
- 處理 tag arguments, 回傳多筆錯誤, debug 訊息收集等場景
Spread Arguments 適合:
- 把陣列變成多個參數傳進函式
- 搭配 Math, console.log, React JSX props 展開
- 提高函式呼叫的彈性與簡潔度
當然可以!這段內容其實展示了 Rest Parameters
和 Spread Operator
在實戰中的非常常見應用,下面我幫你將它們逐一說明得更詳細,包括背後的設計思維、使用情境、以及這樣寫的好處。
實戰應用場景整理:讓你從語法走向實務!
掌握 Rest Parameters
和 Spread Arguments
之後,最重要的是:知道什麼時候要用它們、怎麼用才能讓程式碼更乾淨、彈性更高。
以下這幾個實戰場景就是你將來一定會用到的地方,學會後保證實用一輩子!
建立支援「不定參數數量」的工具函式
📌 範例:每個數字都乘 2 的 multiplyAll()
工具
function multiplyAll(...nums) {
return nums.map(n => n * 2);
}
console.log(multiplyAll(1, 2, 3)); // ➜ [2, 4, 6]
console.log(multiplyAll(10, 20, 30, 40)); // ➜ [20, 40, 60, 80]
🧠 解說:
- 使用
...nums
(Rest Parameters)來接收 任意數量的數字參數。 - 呼叫函式時,不管你傳 1 個、5 個還是 50 個參數,它都能正確處理。
map()
函式能一一處理這些值,讓函式通用性非常高。
✅ 好處:
- 更彈性、不用事先寫死參數數量。
- 更乾淨,不用寫
arguments[0]
這種難懂的語法。 - 非常適合寫「工具類函式」或「數據處理函式」。
使用展開語法,讓陣列資料可以優雅傳入函式
📌 範例:使用 Math.max()
取得最大值
const inputs = [100, 200, 300];
console.log(Math.max(...inputs)); // ➜ 300
🧠 解說:
Math.max()
這個函式原本只能接收像Math.max(1, 2, 3)
這樣的多個參數。- 若你手上已經有一個陣列資料,直接這樣寫會出錯:
Math.max(inputs); // ❌ NaN
- 使用
...inputs
(Spread Operator),就能把陣列「展開」成多個參數傳入,完美解決問題。
✅ 好處:
- 提升函式呼叫的彈性
- 讓已有的資料結構(陣列)可以直接使用,不用再轉換
- 非常適合用在處理 API 回傳資料、計算統計等場景
自訂函式時,參數設計更彈性、使用更直覺
📌 範例:自訂 log 函式支援多條訊息
function customLog(prefix, ...contents) {
contents.forEach(c => console.log(prefix, c));
}
customLog('[DEBUG]', '系統啟動', '載入中', '完成');
// 輸出:
// [DEBUG] 系統啟動
// [DEBUG] 載入中
// [DEBUG] 完成
🧠 解說:
prefix
是固定參數,用來標示每一行訊息的開頭。...contents
是 Rest Parameter,用來接收任意數量的訊息。forEach()
搭配 prefix 一起列印,讓輸出格式一致。
✅ 好處:
- 函式呼叫語法自然又簡潔
- 呼叫者不需要在意你支援幾個參數,直接寫就對了
- 常見於 log 工具、除錯工具、封裝 alert 通知等用途
實戰應用核心重點總結
使用情境 | 使用語法 | 適用工具 |
---|---|---|
接收不定數量參數 | function fn(...args) | 建立通用工具函式 |
展開資料傳入函式 | fn(...array) | 與原生函式、資料操作搭配 |
保留固定參數+彈性傳值 | fn(prefix, ...rest) | 自訂 log / 輸出 / 組字串等 |
🔑 關鍵觀念: Rest 是讓「定義更有彈性」,Spread 是讓「呼叫更有彈性」。
結語:一組 ...
,掌握兩種強大的語法力
你現在已經學會,當 JavaScript 中出現 ...
這三個點時,它可以代表兩種截然不同但又密切相關的用途:
- 在 函式定義中,它是 Rest Parameters(打包):幫你收集不定數量的參數成陣列,讓函式更彈性、更通用。
- 在 函式呼叫或資料結構中,它是 Spread Operator(展開):幫你把陣列或物件展開,靈活組裝、合併或傳參數。
這些語法不只是「看起來新奇的語法糖」,它們是真正能提升你寫程式的效率、可讀性與彈性的關鍵工具,特別是在你寫:
- 多參數工具函式(sum、multiplyAll)
- 彈性 API 操作(logAll、customLog)
- 搭配內建函式(像是
Math.max(...)
) - 或在未來學習 React、Vue 時操作 props、state 時
都會發現它們是不可或缺的日常助手。
學會這兩招,等於讓你的 JS 功力大升級!
在接下來的學習中,當你再看到 ...
出現時,不用再懷疑它在幹嘛了,只要問自己一個問題:
🧠 「它是要收集?還是要展開?」—— 這就決定了它的角色!
未來你會看到這組語法搭配 解構賦值、參數預設值、甚至 事件處理、資料流控制 等高階主題,現在打好基礎,你會走得更快更穩。