JavaScript 初學者必懂:剩餘參數(Rest Parameters) 與展開參數(Spread Arguments)完整解析!

更新日期: 2025 年 3 月 31 日

在 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 ParametersSpread Operator 在實戰中的非常常見應用,下面我幫你將它們逐一說明得更詳細,包括背後的設計思維、使用情境、以及這樣寫的好處。


實戰應用場景整理:讓你從語法走向實務!

掌握 Rest ParametersSpread 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 功力大升級!

在接下來的學習中,當你再看到 ... 出現時,不用再懷疑它在幹嘛了,只要問自己一個問題:

🧠 「它是要收集?還是要展開?」—— 這就決定了它的角色!

未來你會看到這組語法搭配 解構賦值參數預設值、甚至 事件處理、資料流控制 等高階主題,現在打好基礎,你會走得更快更穩。

Similar Posts