火車駕駛

火車駕駛

學習練習

簡介

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 是一位火車駕駛,在城市之間開貨運列車。雖然他們很擅長操作火車,卻不太擅長處理物流或電腦。他們想請你運用自己的程式設計能力,協助整理列車資料,並修正路線資料中的錯誤。

Note

練習時,請使用其餘運算子或展開運算子來解出下列每個任務。

1. 建立所有車廂的陣列

你的朋友一直都記錄著每個車廂的識別碼(ID),但他們永遠不確定系統在任何時刻需要處理多少個車廂。 如果能將這些資料打包成一個統一的array,對物流程式的其他部分來說會輕鬆許多。

實作一個函式 getListOfWagons,它接受任意數量的車廂 ID,也就是每個車廂的 ID。 每個 ID 都會是正整數。 這個函式應該把收到的 ID 以單一array的形式回傳。

getListOfWagons(1, 7, 12, 3, 14, 8, 5);
// => [1, 7, 12, 3, 14, 8, 5]

2. 將前兩個元素移到陣列末端

到這裡,你已經開始對這些資料,以及它們在物流程式中的使用方式有點感覺了。 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]

3. 加入缺少的值

糟糕,有些車廂好像不見了。

幸好,你的朋友剛找到另一個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]

4. 擴充路線資訊

既然所有車廂資料都正確了,你的朋友希望你更新系統的路線資訊。 初始的路線資訊是以object建立而成的,你的朋友希望你用提供的補充資料來更新它。 每條路線需要的資訊都略有不同,所以你的朋友非常希望能有一個通用的解法。

實作一個函式 extendRouteInformation,它接受兩個objects。 第一個object說明了這條列車路線往返於哪些城市之間。

第二個object包含其他路線細節,例如列車速度或長度。 這個函式應該回傳一個整合了所有路線資訊的object。

Note

變數 moreRouteInformation 可以包含不同的屬性。

route = { from: 'Berlin', to: 'Hamburg' };
moreRouteInformation = { length: '100', speed: '50' };
extendRouteInformation(route, moreRouteInformation);
// => {from: "Berlin", to: "Hamburg", length: "100", speed: "50"}

5. 將抵達時間從路線資訊中分離出來

你的朋友發現,路線資訊裡其實不需要抵達時間。 因此,你的朋友希望你將抵達時間從路線資訊中分離出來。

實作一個函式 separateTimeOfArrival,它接受一個包含路線資訊的物件。 這個函式應該回傳一個陣列,其中第一個元素是抵達時間,第二個元素是移除抵達時間後的路線資訊物件。

routeInformation = {
  from: 'Berlin',
  to: 'Hamburg',
  length: '100',
  timeOfArrival: '10:10',
};
separateTimeOfArrival(routeInformation);
// => ["10:10", {from: "Berlin", to: "Hamburg", length: "100"}]
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
JavaScript Exercism

準備好開始 火車駕駛 了嗎?

註冊 Exercism,透過 37 個概念159 個練習 和真人引導來學習並精通 JavaScript,全部免費。