… <= 這個東西不管是在聊天室看到,還是在 Javascript / TypeScript 裡面看到都讓人一頭霧水
這篇要來簡單說明一下當你在前端的程式中看到 … 這代表什麼意思
首先,根據不同的出現場合,它可能代表兩種東西,就像是你朋友小王出現在你家床上,跟出現在熱炒店門口是不同功能。
這篇介紹 … 相關的兩種用法 Spread Syntax、Rest Syntax。
Spread Syntax:把資料展開
Spread Syntax 的作用,就是把原本包在一起的資料展開。
至於「展開」什麼? 這個根據它出現的位置不同而有差異。
- 在函式呼叫或陣列中:此時 … 展開的是 iterable 。例如陣列、字串
const arr = [1, 2, 3]; console.log(...arr); // 等同於 console.log(1, 2, 3) - 在物件中:此時 … 展開的是 物件的可列舉屬性,像這樣
const obj = { a: 1, b: 2 }; const copy = { ...obj }; //把 obj 裡的屬性展開到新的物件中
Spread Syntax的用法,常常用來複製、合併資料,或是在保留原本大部分內容的情況下,只更新其中一部分。
我自己會把重點放在「把 key-value 複製一份出來」這個特性。
來看一個常見情境:切換主題模式(light / dark)。
const settings = {
theme: "light",
fontSize: 14
};
let currentSettings = settings;
document.getElementById("toggleBtn").onclick = function () {
currentSettings = changeMode(currentSettings);
console.log("更新後:", currentSettings);
};
function changeMode(prevSettings) {
return {
...prevSettings,
theme: prevSettings.theme === "light" ? "dark" : "light"
};
}
請把重點放在 changeMode 裡的這一行:
...prevSettings
在這裡,它的作用是把 prevSettings 這個物件中的屬性展開到新的物件裡。
假設 prevSettings 是:
{
theme: "light",
fontSize: 14
}
那麼:
{ {
...prevSettings => theme: "light",
fontSize: 14
} }
然後,程式又多寫了一次 theme:
theme: prevSettings.theme === "light" ? "dark" : "light"
這表示我們要用新的 theme 覆蓋原本展開出來的 theme。
所以最後回傳的結果會是:
{
theme: "dark",
fontSize: 14
}
保留原本的大部分屬性,只覆蓋需要更新的欄位。
如果你還是有點混亂,那可以只記得這個就好
「把原本包在一起的資料(像是陣列或者物件)展開,方便複製、合併或傳遞。」
Rest Syntax:把剩下的資料收集起來
我個人會把 Spread Syntax 和這邊要講的 Rest Syntax 分開理解,建議不熟悉的讀者將這兩個概念分開來理解,對自己會比較有幫助。
那麼 Rest Syntax是什麼呢?
如果說 Spread 是把資料展開,那 Rest 就是把資料收集起來,透過 Rest Syntax 把「剩下的值」收集成一個陣列(或物件)。
使用時重點會放在「收集剩餘資料」。
Rest syntax 常見的出現場景主要有三種:
1. 函式參數(rest parameters)
「不確定有幾個參數」時使用。
function fn(a, ...rest) {
console.log(a); // 第一個參數
console.log(rest);// 剩下的全部(陣列)
}
常見於:
- 參數數量不固定(例如 log、event handler)
- 想把多餘參數集中處理
2. 陣列解構(array destructuring)
const [first, ...rest] = [1, 2, 3, 4];
// first = 1
// rest = [2, 3, 4]
常見於:
- 取頭幾個元素
- 做資料拆分(例如 pagination、queue)
- 物件解構(object destructuring)
const { a, ...rest } = { a: 1, b: 2, c: 3 };
// a = 1
// rest = { b: 2, c: 3 }
常見於:
- 移除某些欄位(例如過濾敏感資料)
- 拆分設定物件
有發現嗎?不論是哪一種出現場景,核心概念都一樣
就是「把剩下的資料收集起來」。
這邊補充一個重要的特性,就是Rest Syntax 使用上「必須放在最後一個位置」。
那麼一樣提供一個簡單例子:記錄操作紀錄。
function logAction(action, ...details) {
console.log("操作:", action);
console.log("細節:", details);
}
logAction("LOGIN");
logAction("DELETE_POST", 12345, "admin");
這時候執行結果:
logAction("LOGIN")
// action = "LOGIN"
// details = []
logAction("DELETE_POST", 12345, "admin")
// action = "DELETE_POST"
// details = [12345, "admin"]
當 ... 出現在函式參數列表中,這個例子是函式參數的使用方式(也就是常見的Rest parameters)。
在這個例子裡,固定要接的第一個參數是 action。
除了 action 以外,後面多傳進來的東西,都會被收進 details 裡。
總結
本篇介紹了 … 所代表的兩種語法:
- Spread(展開) → 把資料「攤開」
- Rest(收集) → 把資料「收起來」
References:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters#syntax
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Destructuring

發佈留言