iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 7
1

緣起

夜喧猴, 簡稱喧猴, 已經到了適婚年齡. 心急如焚的父母為他安排了許多相親活動. 但是相親活動最重要的是什麼?

沒錯, 就是不能犯法, 喧猴看著排山倒海的相親名單, 心中深怕裡面有未成年少女混雜其中, 因此他找上了我們, 來替他的名單把關, 同時也為國家的法律把關.

任務目標

我們將收到一份陣列, 裡面有數個相親候選人的資料, 利用陣列提供的原型方法檢查相親候選人資料是否合格.
資料如下:

const fiancee = [
  { name: 'Tomato', year: 1989 },
  { name: 'Totoro', year: 1896 },
  { name: 'Jedi', year: 2008 },
  { name: 'Judy', year: 1970 },
  { name: 'Dudi', year: 1969 },
  { name: 'David', year: 1950 }
];

作法

要確定這份名單有無藏匿未成年少女, 我們可以使用every()方法

Array.prototype.every(callback)

一個陣列中所有的元素通過自訂的回呼函式所給定的測試, 回傳的結果為true, 反之, 若有其中一項沒通過測試, 結果為false

因此只要測試條件為「所有人都都是成年人嗎?」就好, 程式碼如下:

const allAdults = fiancee.every(person => (new Date()).getFullYear() - person.year >= 18);
console.log(allAdults)

Date()物件的getFullYear()方法能夠得到當下時間西元年的值, 只要今年減去出生日期就能知道是否成年. 不出意外, 回傳結果為false. 這份名單有問題!

「慢...慢著!」喧猴驚慌地喊著, 「總不會這麼倒霉, 這份名單裡面的人都是未成年少女吧?」

喧猴懷抱著一絲希望, 他相信這裡面一定有和他一樣達到適婚年齡的對象, 為了幫助喧猴, 我們可以用另一個陣列原型方法some()來檢查裡面是否有一個以上的成年女子.

Array.prototype.some(callback)

一個陣列中只要有一個以上的元素通過自訂的回呼函式所給定的測試, 回傳的結果為true, 反之, 若全部都沒通過測試, 結果為false

這次的測試條件為「裡面含有一個以上的成年人嗎?」, 程式碼如下:

const hasAdult = fiancee.some(person => (new Date()).getFullYear() - person.year >= 18);
console.log(hasAdult)

回傳結果為true, 有成年人啊! 看著喧猴, 我們為他鬆了口氣.

接下來我們只要用filter()找到未成年的少女們, 再將她們濾出名單就好.

「慢...慢著!」喧猴又有意見了, 「我能夠看看那名未成年的少女嗎?」 雖然不知道喧猴想做什麼, 但這點小任務, 也是可以用陣列原型方法find()來達成.

Array.prototype.find(callback)

回傳第一個通過自訂的回呼函式測試的內容.

這個方法和filter()很像, 差別在於它只能回傳第一個通過測試的內容, 而非全部.

用這個方法, 我們可以找到排在名單最前面的未成年少女, 但是假設後面還有未成年少女, find()是找不到的. 程式碼如下:

const girl = fiancee.find(person => (new Date()).getFullYear() - person.year <= 18);
console.log(girl)

回傳結果為Jedi, 出生於2008年, 今年9歲.
是一名九歲的絕地武士啊, 是最後的絕地武士嗎!

不管如何先將其移出名單吧.

Array.prototype.findIndex(callback)

回傳第一個通過回呼函式測試的元素的index.

使用一樣的篩選條件作為函式內容, 我們可以鎖定Jedi儲存在陣列的哪個位置. 之後用slice()方法可以將其切出陣列外.

Array.prototype.slice(begin, [, end])

slice()可以將某個陣列的片段複製為一個新的陣列. 可輸入兩個參數, 第一個代表頭, 從哪邊切割. 第二個代表尾, 切割到哪邊. 可以只輸入頭, 代表只切頭, 也可都不輸入, 代表直接複製整個函式.

混合使用上述兩個方法, 可以產生一份將Jedi過濾後的名單, 程式碼如下:

    const girlIndex = fiancee.findIndex(person => (new Date()).getFullYear() - person.year <= 18);

    const newFiancee = [
      ...fiancee.slice(0, girlIndex),
      ...fiancee.slice(girlIndex + 1)
    ];
    console.log(newFiancee)

新的名單是由兩段切割後的陣列所組成, 第一段是從頭切到Jedi前, 第二段是Jedi後切到尾, 剛好就是沒有Jedi!

其實還有另一個方法可以達成一樣的效果, 就是splice()方法.

Array.prototype.splice(begin, deleteCount)

splice()方法能夠從指定的位置開始移除指定數目的陣列欄位. 回傳的值為被刪掉的欄位

特別注意的是, splice()方法會直接對原陣列作用, 因此若不想更動原陣列, 可以先複製後再使用. 程式碼如下.

// 先用slice()複製
const newFiancee = fiancee.slice();
// 再切割複製後的陣列
newFiancee.splice(girlIndex, 1);
console.log(newFiancee)

到此任務完成!!

以上就是 JS30 第七篇.

Reference

Array 方法們, 在右邊那排
練習的完整程式碼

後談

「慢...慢著!」喧猴還來啊? 「那份名單我不要了, 我可以要這個嗎?」 喧猴拿著find()方法得到的那個唯一名單.

「這不是未成年少女嗎?」我無法理解.

喧猴指了指自己略顯衰老的面龐, 幸福的說著:「我想過了, 就像我的臉是老起來放一樣, 少女也可以放起來老啊... 我願意等她十年...」

嗯, 就這樣, 喧猴波瀾壯闊的愛情長跑正式開始!


上一篇
Day 6 - Type Ahead
下一篇
Day 8 - HTML Canvas
系列文
JS30 錄30

1 則留言

0
王郁翔
iT邦新手 5 級 ‧ 2017-12-26 13:25:12

願猿力與你同在!

Arel iT邦新手 5 級 ‧ 2017-12-26 13:58:38 檢舉

猿力與你同在! 金奎剛

我要留言

立即登入留言