iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Modern Web

JS30 x 鐵人30 x MDN doc系列 第 4

[Day4] - Array Cardio part1(JS30 x 鐵人 30 x MDN)

  • 分享至 

  • xImage
  •  

今天來玩玩 Array method,並印出結果吧-趴萬

觀察 index-Start.html 的 Javascrript 部分,總共有 8 小題,每題有限制要使用哪種 Array method 完成題目需求,並用於 console 中印出答案

  1. Filter the list of inventors for those who were born in the 1500's (篩選出生於 15 世紀的發明家們)

這題使用到Array.prototype.filter(),這個 Array method 會回傳一個新的陣列,所以我們宣告一個變數名為 fifteenthCenturyiInventors 來儲存回傳的結果,用陣列 inventors(發明家們)去 filter(篩選)其中的每一位 inventor(發明家)的出生 year 是否介於十五世紀(這邊我覺得 key 值改叫 birth 或 born 會更直白一點),如果判斷成立則保留這一位 inventor(發明家),不成立則去掉。

const fifteenthCenturyiInventors = inventors.filter(
  (inventor) => inventor.year >= 1500 && inventor.year < 1600
);
//你也可以寫成下面這樣
//const fifteenthCenturyiInventors = inventors.filter(isBornIn15thCentury);
//function isBornIn15thCentury(people){
// return people.year >= 1500 && people.year < 1600
//}

console.table(fifteenthCenturyiInventors);
  1. Give us an array of the inventors first and last names(給我們一個陣列裡面只裝發明家們的全名)

這題使用到Array.prototype.map(),這個 Array method 也會回傳一個新的陣列,將遍歷陣列中的每個元素,將元素分別傳入你指定的函式,最後將各個元素執行函式的返回值組成一個新的陣列,所以我們宣告一個變數名為 inventorsNames 來儲存回傳的結果,用陣列 inventors(發明家們)去 map(映射)其中的每一位 inventor(發明家)將他們的 first name 與 last name 串接成一個字串(即 full name 全名)回傳,產生的結果陣列每一項將不再是 Object 而是 String。

const inventorsName = inventors.map(
  (inventor) => inventor.first + " " + inventor.last
);
console.log(inventorsName);
  1. Sort the inventors by birthdate, oldest to youngest(按照發明家出生年排序,先出生>後出生)

這題使用到Array.prototype.sort(),這個 Array method 會直接修改原本的陣列,將依照你設定方式進行每一項的排序,所以我們宣告一個變數 inventorSeniority 儲存依照出生先後的排序結果,為避免改到原本的陣列使用 [...inventors]解構賦值的方式進行陣列拷貝,再拿拷貝的陣列進行sort(排序),排序的依據是inventor(發明家)的出生年(year)進行年份升序排列,其中a代表用於比較的第一個元素,b代表用於比較的二個元素,如果判斷成立則返回1,這時將把a排在b之後。不成立則返回-1,這時將把a排在b之前。
另外因為我們用來排序比較的值是純數字類型所以可以簡寫成(a.year - b.year)

const inventorSeniority = [...inventors].sort((a, b) =>
  a.year > b.year ? 1 : -1
);
// const inventorSeniority = [...inventors].sort((a, b) => a.year - b.year);
console.log(inventorSeniority);
  1. How many years did all the inventors live all together?(算出發明家總歲數)

這題使用到Array.prototype.reduce(),這個 Array method 比較複雜,第一個參數為 callback 函式(函式內必須至少有兩個參數,第一個參數為accumulator(累加器),第二個參數為currentValue(當前元素)),第二個參數為初始值。
⚠️ 第一輪迭代累加器又等於初始值。
⚠️callback 函式最後別忘了 return 一個累加器給第二輪迭代使用。

這次我們宣告一個變數 inventorsAllLive 儲存最後加總後的結果,然後用陣列 inventors(發明家們)去 reduce(累加/歸納),因為要算總歲數加總,所以先設定初始值為0,在 callback 中每次迭代累加器都加上當前這位發明家的歲數(即逝世年減出生年)然後回傳給下次迭代使用,最後加總的總歲數就會賦值存在 inventorsAllLive 中。

const inventorsAllLive = inventors.reduce((acc, inventor) => {
  return (acc += inventor.passed - inventor.year);
}, 0);
console.log(inventorsAllLive);

5~8 題依舊使用上方幾種 Array method,語法怎麼寫我就不再多做贅述,若還是不懂的話,MDN的範例一定可以教會你

  1. Sort the inventors by years lived(按照發明家壽命排序,長壽>短壽)
    先宣告一個變數 inventorAge 儲存依照壽命的排序結果,一樣為避免改到原本的陣列使用解構賦值進行陣列拷貝,再拿拷貝的陣列進行 sort(排序),這次排序的依序是壽命進行降序排列,所以寫法我們變成是算出 b 後者的壽命(b.passed - b.year)再減去 a 前者的壽命(a.passed - a.year)當作值回傳
const inventorAge = [...inventors].sort(
  (a, b) => b.passed - b.year - (a.passed - a.year)
);
//const inventorAge = [...inventors].sort(
//  (a, b) => {
//  const bLife = b.passed - b.year;
//  const aLife = a.passed -a.year;
//  return bLife > aLife ? 1 : -1
//  }
//);
console.table(inventorAge);
  1. create a list of Boulevards in Paris that contain 'de' anywhere in the name(從網頁上創造一個陣列,裡面存放所有包含"de"字段的巴黎林蔭大道) https://en.wikipedia.org/wiki/Category:Boulevards_in_Paris

這題我原先還搞不懂要做什麼,還傻傻的 🙃 從網頁上複製所有林蔭大道名稱下來存放在一個陣列內然後再篩選 👇

const parisBoulevards = ["Boulevard Auguste-Blanqui", ...+38];
const containDE = parisBoulevards.filter((boulevards) =>
  boulevards.includes("de")
);
console.table(containDE);

後面看詳解第一句才驚覺是要直接到網頁的 console 使用前幾天的節點選取並利用元素屬性篩選創造陣列。

觀察目標網頁可以發現存放名稱的位置都在html <a> tag中但本身沒有 class 或 id,如果我們直接 queryselectorAll("a")那將取到整個網站的所有連結,包含不是林蔭大道名稱的裡面當然也有可能包含"de"導致結果出錯。

所以我們要更精確的選到只包含 39 個林蔭大道,那我們往外層看<a>👉<li>👉<h3><ul>👉<div class="mw-category-group">終於找到一個有標示性 class 的且所有林蔭大道名稱都位於這個結構之下,於是我們就用這個來取 nodeList 吧!

  • 宣告一個變數 boulevards 來儲存 nodeList,注意因為 nodeList 是類陣列,雖然它能用 forEach method 但它終究不是真的陣列,無法使用其他 javascript 的 Array method,但我們可以使用 Array.form()或[...nodeList]的方式複製後便能使用所有 Array method
  • 宣告一個變數 DEboulevard,以 boulevards 陣列先用 map method(遍歷)回傳每一個 node 的textContent,因為 map 回傳的是一個陣列所以我們可以在後面緊接著使用 filter method(篩選)名稱包含"de"的林蔭大道當作結果儲存在 DEboulevard 中。
const boulevards = [...document.querySelectorAll(".mw-category-group a")];
const DEboulevard = boulevards
  .map((node) => node.textContent)
  .filter((BoulevardName) => BoulevardName.includes("de"));
console.log(DEboulevard);
  1. Sort the people alphabetically by last name(根據人名的姓氏排列)
const people = ["Bernhard, Sandra","Bethea, Erin"...+39項]

觀察資料發現都是字串,既然要以姓氏排列 sort 裡面的比較的 a 與 b 我們就要先用String.prototype.split()將全名切割成陣列並以姓與名之間都有的", "當作切割點,結果會是一個陣列,index[0]代表姓氏,index[1]代表名字,這樣我們就能依照姓氏排列了。

const sortPeople = people.sort((a, b) => {
  // const [alast, afirst] = a.split(", ");
  // const [blast, bfirst] = b.split(", ");
  // return alast > blast ? 1 : -1;
  return a.split(", ")[0] > b.split(", ")[0] ? 1 : -1;
});
console.table(sortPeople);
  1. Sum up the instances of each of these(加總陣列內的交通方式出現幾次?)
const data = [
  "car",
  "car",
  "truck",
  "truck",
  "bike",
  "walk",
  "car",
  "van",
  "bike",
  "walk",
  "car",
  "van",
  "car",
  "truck",
];

根據題目意思跟資料我這樣解釋不確定恰不恰當,既然要算交通方式重複出現的次數,那最終的資料型態應該就是 Object 了,並把每種交通方式當作 key 值,每次於陣列內出現就加 1 次,如何從一個陣列變成物件,這就要再次用到強大的reduce() method,並把初始值設定為一個空物件{},這邊利用到空值合併運算子??每次迭代先判斷累加器物件的[item]存不存在,如果 undefined 則先賦值0,再加上 1 次,以便不會發生undefined + 1 = NaN的狀況。

const sum = data.reduce((acc, item) => {
  acc[item] = (acc[item] ?? 0) + 1;
  return acc;
}, {});
console.table(sum);

👉Github Demo 頁面 👈

👉 好想工作室 15th 鐵人賽看板 👈

參考資料

  1. Javascript 30 官網
    https://javascript30.com/
  2. MDN 官網
    https://developer.mozilla.org/en-US/

上一篇
[Day3] - CSS Variables(JS30 x 鐵人 30 x MDN)
下一篇
[Day5] - Flex Panel Gallery(JS30 x 鐵人 30 x MDN)
系列文
JS30 x 鐵人30 x MDN doc30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言