JavaScript 有一個內建的...運算子,讓你在處理數量不定的元素時更加方便。依照使用情境,它會稱為其餘運算子(英文:rest operator)或展開運算子(英文:spread operator)。
當...出現在賦值的左側時,這三個點就稱為rest運算子。這三個點加上一個變數名稱,稱為其餘元素。它會收集零個或多個值,並將它們存進單一陣列中。
const [a, b, ...everythingElse] = [0, 1, 1, 2, 3, 5, 8];
a;
// => 0
b;
// => 1
everythingElse;
// => [1, 2, 3, 5, 8]
請注意,在 JavaScript 中,有別於某些其他語言,其餘元素後面不能有尾隨逗號。它一定要是解構賦值中的最後一個元素。下面的範例會擲出SyntaxError:
const [...items, last] = [2, 4, 8, 16]
和陣列類似,其餘運算子也可以用來收集一個或多個物件屬性,並將它們存進單一物件中。
const { street, ...address } = {
street: 'Platz der Republik 1',
postalCode: '11011',
city: 'Berlin',
};
street;
// => 'Platz der Republik 1'
address;
// => {postalCode: '11011', city: 'Berlin'}
當...出現在函式定義中最後一個引數旁邊時,那個參數就稱為其餘參數(英文:rest parameter)。它讓函式能以陣列的形式接受數量不定的引數。
function concat(...strings) {
return strings.join(' ');
}
concat('one');
// => 'one'
concat('one', 'two', 'three');
// => 'one two three'
當...出現在賦值的右側時,它稱為spread運算子。它會把陣列展開成一串元素。和其餘元素不同的是,它可以出現在陣列實體運算式的任何位置,而且可以有不只一個。
const oneToFive = [1, 2, 3, 4, 5];
const oneToTen = [...oneToFive, 6, 7, 8, 9, 10];
oneToTen;
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const woow = ['A', ...oneToFive, 'B', 'C', 'D', 'E', ...oneToFive, 42];
woow;
// => ["A", 1, 2, 3, 4, 5, "B", "C", "D", "E", 1, 2, 3, 4, 5, 42]
和陣列類似,展開運算子也可以用來把屬性從一個物件複製到另一個物件。
let address = {
postalCode: '11011',
city: 'Berlin',
};
address = { ...address, country: 'Germany' };
// => {
// postalCode: '11011',
// city: 'Berlin',
// country: 'Germany',
// }
你的朋友 Linus 是一位火車駕駛,在城市之間開貨運列車。雖然他們很擅長操作火車,卻不太擅長處理物流或電腦。他們想請你運用自己的程式設計能力,協助整理列車資料,並修正路線資料中的錯誤。
練習時,請使用其餘運算子或展開運算子來解出下列每個任務。
你的朋友一直都記錄著每個車廂的識別碼(ID),但他們永遠不確定系統在任何時刻需要處理多少個車廂。
如果能將這些資料打包成一個統一的array,對物流程式的其他部分來說會輕鬆許多。
實作一個函式 getListOfWagons,它接受任意數量的車廂 ID,也就是每個車廂的 ID。
每個 ID 都會是正整數。
這個函式應該把收到的 ID 以單一array的形式回傳。
getListOfWagons(1, 7, 12, 3, 14, 8, 5);
// => [1, 7, 12, 3, 14, 8, 5]
到這裡,你已經開始對這些資料,以及它們在物流程式中的使用方式有點感覺了。 ID 系統一律將火車頭的 ID 指定為1,列車中其餘的車廂則會被隨機指定一個大於1的 ID。
你的朋友接了兩節新車廂到列車上,卻忘了更新系統!
現在必須把列車array中的前兩節車廂移到最後面,否則整個順序都會亂掉。
如果你能幫 Linus 修正這些錯誤,他們會非常感激。
實作一個函式 fixListOfWagons,它接受一個包含每個車廂 ID 的陣列。
它會return一個array,其中前 2 個元素會被移到array的末端,讓火車頭能在最前面。
eachWagonsID = [2, 5, 1, 7, 4, 12, 6, 3, 13];
fixListOfWagons(eachWagonsID);
// => [1, 7, 4, 12, 6, 3, 13, 2, 5]
糟糕,有些車廂好像不見了。
幸好,你的朋友剛找到另一個array,裡面似乎裝著遺失的車廂 ID,並希望你能把它們加進主要的車廂 IDarray。
他們只記得,這些遺失的值應該放在指定的火車頭正後方。
根據這些新資訊,寫一個名為 correctListOfWagons 的函式,它接受兩個陣列作為引數,這兩個陣列分別包含每個車廂的 ID。
第二個array的車廂 ID 應該加進第一個array中,直接放在火車頭(ID 1)之後。
eachWagonsID = [1, 5, 20, 7, 4, 8];
missingWagons = [3, 17, 6, 15];
correctListOfWagons(eachWagonsID, missingWagons);
// => [1, 3, 17, 6, 15, 5, 20, 7, 4, 8]
既然所有車廂資料都正確了,你的朋友希望你更新系統的路線資訊。
初始的路線資訊是以object建立而成的,你的朋友希望你用提供的補充資料來更新它。
每條路線需要的資訊都略有不同,所以你的朋友非常希望能有一個通用的解法。
實作一個函式 extendRouteInformation,它接受兩個objects。
第一個object說明了這條列車路線往返於哪些城市之間。
第二個object包含其他路線細節,例如列車速度或長度。
這個函式應該回傳一個整合了所有路線資訊的object。
變數 moreRouteInformation 可以包含不同的屬性。
route = { from: 'Berlin', to: 'Hamburg' };
moreRouteInformation = { length: '100', speed: '50' };
extendRouteInformation(route, moreRouteInformation);
// => {from: "Berlin", to: "Hamburg", length: "100", speed: "50"}
你的朋友發現,路線資訊裡其實不需要抵達時間。 因此,你的朋友希望你將抵達時間從路線資訊中分離出來。
實作一個函式 separateTimeOfArrival,它接受一個包含路線資訊的物件。
這個函式應該回傳一個陣列,其中第一個元素是抵達時間,第二個元素是移除抵達時間後的路線資訊物件。
routeInformation = {
from: 'Berlin',
to: 'Hamburg',
length: '100',
timeOfArrival: '10:10',
};
separateTimeOfArrival(routeInformation);
// => ["10:10", {from: "Berlin", to: "Hamburg", length: "100"}]