在學習 JavaScript 的過程中,你可能會發現一個很特別的現象:
當我們呼叫某個函式時,傳入的參數數量似乎不需要完全符合函式定義時所寫的數量,甚至可以多傳幾個參數,或是少傳,程式也不會報錯,依然能夠正常執行。
讓我們來看一個簡單的例子:
function greet(name) {
console.log("Hello, " + name + "!");
}
greet("Alice"); // → Hello, Alice!
greet("Bob", "Hi"); // → Hello, Bob!
greet(); // → Hello, undefined!在這個例子中,我們定義了一個 greet 函式,它只需要一個 name 參數:
- 當我們只傳入一個參數(
"Alice")時,會正常顯示Hello, Alice!。 - 當我們多傳一個參數(
"Hi"),JavaScript 會忽略第二個多出來的參數,仍然只拿"Bob"當作name。 - 更特別的是,如果我們什麼都不傳,
name的值會變成undefined,這樣程式仍然可以執行,只是輸出會是Hello, undefined!。
這到底是怎麼回事呢?這正是 JavaScript 函式的一個重要特性:「參數是選擇性的(optional)」,也就是說——
JavaScript 函式並不會嚴格檢查參數的數量,只會根據實際傳入的值來運作。
這種彈性設計雖然讓 JavaScript 程式變得更寬容、更方便,但也容易讓初學者出現誤解或執行上的錯誤。
如果不小心少傳參數,可能會出現 undefined 造成不預期的結果;如果多傳,也可能讓多餘的資訊被忽略掉而浪費資源。
因此,這篇文章會一步步帶你深入理解這種「選擇性參數」的運作方式,讓你在寫函式或呼叫函式時能夠更有信心、也更不容易出錯。
什麼是「選擇性參數」?
在很多程式語言中,當你呼叫一個函式時,必須準確地傳入所有需要的參數,否則會出錯或中斷執行。
但在 JavaScript 中,這件事情被設計得「很寬鬆」。也就是說:
JavaScript 的函式可以接收比你定義時「更多」或「更少」的參數,而且不會報錯。
這種特性讓開發者在使用函式時更有彈性,也因此產生了所謂的「選擇性參數」概念(Optional Parameters)。我們可以根據實際情況決定是否要傳入某些參數,而函式會依照你提供的參數,自動調整自己的行為。
範例一:參數傳太多了怎麼辦?
function square(x) {
return x * x;
}
console.log(square(4, true, "hedgehog"));
// 輸出:16說明:
上面這段程式碼中,我們定義了一個 square 函式,它只需要一個參數 x,並回傳 x * x 的結果。照理來說,我們應該只傳入一個數字,例如 square(4)。
但實際上,我們傳入了三個參數:
square(4, true, "hedgehog");神奇的是,JavaScript 並不會報錯,也不會警告你傳太多參數了。它只會乖乖地:
- 把第一個參數
4指派給變數x - 完全忽略後面的
true和"hedgehog"
也就是說,執行過程中 square(4, true, "hedgehog") 的效果,其實和 square(4) 一模一樣。因為函式裡只使用了 x,根本沒有定義或處理後面的參數。
這種「超量容忍」的特性,是 JavaScript 的一種預設行為。雖然很方便,但在複雜程式中如果不小心多傳了參數,卻被默默忽略,可能會讓錯誤變得更難發現。
如果參數傳太少又會怎樣?
那反過來,如果我們傳入的參數「比函式需要的還少」呢?答案是:
JavaScript 會自動幫你把「缺少的參數」補上
undefined。
也就是說,函式裡的參數變數還是存在,只是它們的值是 undefined。
傳少了參數,函式會怎麼反應?
function minus(a, b) {
if (b === undefined) return -a;
else return a - b;
}
console.log(minus(10));
// 輸出:-10
console.log(minus(10, 5));
// 輸出:5說明:
這個 minus 函式的設計很特別,它有兩種行為:
- 如果只傳一個參數,也就是
b沒有傳,會進入if判斷,把b === undefined判定為 true,結果就會回傳-a。 - 如果兩個參數都傳了,就會回傳
a - b,進行一般的減法。
minus(10); // 只傳 a,b 是 undefined,所以回傳 -10
minus(10, 5); // 傳 a 和 b,正常減法,結果是 5這樣的技巧讓函式變得更有彈性,也讓你可以根據「實際傳入的參數數量」來決定執行邏輯。
這樣設計有什麼風險?
雖然選擇性參數聽起來很方便,但它也有潛在風險:
- 錯誤可能被「靜靜地吞掉」:如果你不小心少傳了參數,JavaScript 不會告訴你,只會默默給它
undefined,這在某些情況下可能導致不明錯誤或奇怪的運算結果。 - 維護時不易追錯:當你在大型專案中修改函式,或是別人呼叫你的函式時,若沒明確註明哪些參數是必要的,別人可能會誤用或忽略重要參數。
因此,雖然這是 JavaScript 的一種自由特性,但在使用時仍然建議加上:
- 明確的預設值
- 條件判斷是否有傳入參數
- 或是使用 TypeScript(可選)來進一步嚴格檢查
預設值怎麼用?
在前面的章節我們提到,當函式的參數沒被傳入時,它的值就會變成 undefined。
這雖然是 JavaScript 的正常行為,但有時候我們會希望:「如果使用者沒傳這個參數,就自動幫他填一個預設的值」,這樣程式比較不容易出錯。
為了解決這個問題,JavaScript 提供了預設參數值(default parameter)的語法,讓你可以在函式定義時直接寫好「備用值」。
範例一:點飲料,沒說糖度就給半糖
我們來看一個生活化的例子。
想像你寫了一個點飲料的函式,讓使用者輸入飲料名稱和糖度。
如果他沒說糖度,就預設給他「半糖」。
function orderDrink(drink, sugar = "半糖") {
console.log(`您點了一杯 ${sugar} 的 ${drink}`);
}
orderDrink("珍奶");
// → 您點了一杯 半糖 的 珍奶
orderDrink("紅茶", "無糖");
// → 您點了一杯 無糖 的 紅茶說明:
這裡的 sugar = "半糖" 就是設定預設值的寫法。
- 第一個例子只傳了「飲料名稱」,沒講糖度,所以函式自動套用預設的「半糖」。
- 第二個例子明確指定「無糖」,函式就會使用你提供的值。
這樣做的好處是,使用者可以只填他在意的選項,其他就讓系統幫忙補上合理的預設值。
傳入 undefined,也會使用預設值
orderDrink("綠茶", undefined);
// → 您點了一杯 半糖 的 綠茶這裡雖然有傳入第二個參數,但值是 undefined,JavaScript 仍然會套用預設的「半糖」。
但要注意,如果你傳的是 null,那就不會使用預設值囉:
orderDrink("烏龍茶", null);
// → 您點了一杯 null 的 烏龍茶這是因為 null 是一個「有效的值」,不是「沒傳東西」,所以函式會照單全收。
預設值讓程式更有彈性
使用預設值有幾個好處:
- ✔️ 使用者可以少打一點參數,程式幫忙補上合理預設
- ✔️ 不怕沒傳參數導致
undefined出錯 - ✔️ 程式碼更清楚也更容易維護
這種寫法在開發中非常常見,尤其當你的函式會被不同人、在不同情境下使用時,設定好預設值就是一種保險。
如何接收不定數量的參數?
有時候,在寫函式的時候,我們不會事先知道「使用者會傳幾個參數」給這個函式。
例如,你寫一個「點餐」的函式,有的人只點一樣餐點,有的人點了五樣、十樣都有可能。
這時候如果函式只能固定接兩個、三個參數,就會很不方便。
所以 JavaScript 提供了一個超實用的語法,叫做 ...(三個點),這種寫法叫做「剩餘參數(rest parameter)」。
它的功能是:
🔧 把你呼叫函式時「多個傳進來的參數」,全部打包收集起來,變成一個陣列。
陣列是什麼?
當我們需要儲存很多資料時,可以用很多變數這樣寫:
let item1 = "薯條";
let item2 = "雞塊";
let item3 = "可樂";雖然這樣可以記錄三筆資料,但一旦資料變多,就會變得非常不好管理。
這時候,我們就可以用「陣列」來幫忙!
✅ 陣列是一種「可以一次放很多資料」的變數
你可以把陣列想成一排收納格,像這樣:
櫃子 = [ "薯條", "雞塊", "可樂" ]
格子編號: 0 1 2在 JavaScript 中,你可以用這種方式建立一個陣列:
let snacks = ["薯條", "雞塊", "可樂"];這個陣列 snacks 裡面放了三個字串,分別代表三樣東西。而每一樣東西都有一個「位置編號」,也就是我們說的 索引(index)。
這個編號從 0 開始,不是從 1。
🧠 為什麼從 0 開始?
JavaScript(還有很多程式語言)在設計上,就是用「第 0 格」代表第一筆資料,這是電腦記憶體結構的習慣。
如果你之後學更多語言,也會發現這是一種共通規則。
🧪 如何從陣列中拿出資料?
如果你要拿出陣列裡的某一筆資料,可以用「陣列名稱 + 中括號」的寫法,像這樣:
console.log(snacks[0]); // → 薯條
console.log(snacks[1]); // → 雞塊
console.log(snacks[2]); // → 可樂這表示:
snacks[0]是第一筆資料snacks[1]是第二筆資料snacks[2]是第三筆資料
這樣我們就可以很方便地一次儲存、一次處理多筆資料,而不用寫一堆變數。
🧰 陣列還能做什麼?
除了存東西、拿東西,陣列還有很多很強大的功能,例如:
.length:看裡面有幾筆資料.push():往陣列後面加東西.pop():把最後一筆資料拿掉for迴圈:一筆一筆跑過整個陣列
那 ...參數 到底怎麼把參數變成陣列?
當你在定義函式時,用 ...參數名 這個語法,JavaScript 就會自動幫你做一件事:
把「你傳進來的所有參數」,通通打包成一個陣列!
來看一個實際例子:
function orderFood(...items) {
console.log(items);
}
orderFood("滷肉飯", "紅茶", "炸雞");執行結果會是:
["滷肉飯", "紅茶", "炸雞"]也就是說,雖然我們傳進去的是三個獨立的值:
"滷肉飯", "紅茶", "炸雞"但在函式裡面,它們會自動被包起來,變成這樣:
let items = ["滷肉飯", "紅茶", "炸雞"];這個 items 就是陣列,裡面裝的就是你傳進來的所有資料。
🧠 換句話說
當你這樣定義函式:
function something(...data) { }那麼你呼叫:
something("A", "B", "C");JavaScript 背後其實幫你做的事情是:
let data = ["A", "B", "C"];你就可以用 data[0]、data[1] 去讀取每一筆資料,也可以用 data.length 看總共有幾筆。
為什麼這很重要?
在寫函式的時候,最麻煩的一件事就是:「我不知道別人會傳幾個參數給我!」
傳太少 → 可能會出錯;
傳太多 → 傳進來卻沒人接,白白浪費;
而且有時候你還得寫很多 if 去檢查有沒有傳值。
但如果你使用 ...參數(剩餘參數語法),這些問題就會簡單很多。
因為它會把你傳進來的所有參數自動包成一個陣列,你就能像處理一份清單一樣,一次處理全部的資料。
而且你不需要自己一個一個接,只要寫一個變數名,就能把參數通通接起來,這是它最厲害的地方。
🧪 範例:點餐時接收不定數量的菜名
現在我們來寫一個點餐系統的函式。
這個函式叫做 orderFood,會印出使用者點了哪些菜。
你不確定對方會點幾道菜,所以你用 ...dishes 這個語法,讓函式可以一次接收「任意數量」的菜名。
function orderFood(...dishes) {
console.log("您點的餐有:");
for (let i = 0; i < dishes.length; i++) {
console.log("- " + dishes[i]);
}
}這個函式裡做了三件事:
- 宣告一個剩餘參數
...dishes,把所有傳進來的菜名打包成陣列 - 印出提示文列裡字「您點的餐有:」
- 用
for回圈,一個一個印出陣的每一道菜
現在來呼叫這個函式看看:
orderFood("滷肉飯");
orderFood("牛肉麵", "水餃", "紅茶");🖨️ 執行結果:
您點的餐有:
- 滷肉飯
您點的餐有:
- 牛肉麵
- 水餃
- 紅茶🧠 怎麼理解這段程式?
我們來仔細看看這行:
function orderFood(...dishes)這裡的 ...dishes 是最重要的關鍵:
| 部分 | 說明 |
|---|---|
... | 三個點的語法,代表「剩餘參數」的開始 |
dishes | 接收的變數名稱,可以自己取名(這裡用 dishes 代表「一道道菜」) |
🧩 程式內部實際的變化會長這樣:
當你這樣呼叫:
orderFood("牛肉麵", "水餃", "紅茶");JavaScript 背後會幫你把這三個參數打包成陣列:
let dishes = ["牛肉麵", "水餃", "紅茶"];所以你可以像處理陣列一樣,一個一個拿出來印出來、加總、統計都可以。
🧪 再進一步觀察:為什麼 dishes.length 可以用?
因為 dishes 是一個陣列,而陣列都有 .length 屬性,表示它裡面總共有幾筆資料。
console.log(dishes.length); // → 3而我們用這個 .length 來跑 for 迴圈:
for (let i = 0; i < dishes.length; i++) {
console.log("- " + dishes[i]);
}i會從 0 開始- 每次跑一圈,就印出
dishes[i] - 一直跑到印完最後一筆為止
這就是一種最基本的「一個一個跑過陣列」的方式。
結語:掌握彈性,提高程式設計能力
「選擇性參數」是 JavaScript 函式設計的一個重要特色,掌握這個特性不僅能夠提高你撰寫函式的靈活度,也能夠讓你更容易讀懂別人所寫的程式碼。
優點:
- 使用彈性高,可根據情境調整參數數量。
- 可為函式參數設定預設值,提升程式碼的可讀性。
缺點(要注意的地方):
- JavaScript 不會自動提醒你參數數量有問題,容易造成程式運作上的疏漏。
- 使用時必須更加注意參數傳入的狀況,避免產生意外的錯誤。\
在未來學習更多進階技巧時,這些基礎觀念都會成為你最大的助力。
希望透過這篇文章,你能夠深入理解並靈活運用這些參數技巧!