iT邦幫忙

2022 iThome 鐵人賽

DAY 3
0

唯有全然的了解,才有資格說愛或恨。

Leonardo da Vinci

此文討論Array為主,但可能會牽扯些許Object。

如果你跟JS打交道一段時間,Array與Object不一定是最愛,但也一定是摯友。對於Promise或Closure,你可以斬釘截鐵透露出漠然,但對於Array與Object,你絕對會侃侃而談。但其實,只有你自己知道,內心深處對他們總有些許的緊張與不安。

正因為這層關係,你連他們相關的methods都瞭若指掌。這樣的你,於我,可能已經非常完美。但如果你還記得我昨天那位FP控老闆,我就不好說了。以下我提供一些可能會惹怒他的三個例子:

例子一:push方法

問題定義。 FP控老闆現在給你:(1)團隊中,在美國出生的成員bornInAmericaEmployees;(2)團隊中,是華人的成員ChineseEmployees。請你找出團隊中的ABCABCEmployees

如果要惹怒他,我推薦這樣寫:

// 可能會被FP老闆討厭的寫法
// imperative paradigm
const bornInAmericaEmployees = ["Mira", "Peter", "Austin"];
const ChineseEmployees = ["Mira", "Allen", "Ryvn"];

const ABCEmployees = [];

for (const ChineseEmployee of ChineseEmployees) {
    if (bornInAmericaEmployees.includes(ChineseEmployee)) {
        ABCEmployees.push(ChineseEmployee);
    }
}

console.log(ABCEmployees); // ["Mira"]

在這個例子中,FP控老闆討厭的點有兩個:

  1. 這個例子把arrayABCEmployees宣告在迴圈之外。
  2. 這個例子用push方法填充array。

每當大家要用push方法之前,可以想想看可不可以用declarative方式取代之。因為push方法會改變(mutate)array。

為了討他歡心,或許你可以改成這樣:

// 較受FP老闆喜歡的寫法
// declarative paradigm
const bornInAmericaEmployees = ["Mira", "Peter", "Austin"];
const ChineseEmployees = ["Mira", "Allen", "Ryvn"];

const ABCEmployees = ChineseEmployees.filter(
    (ChineseEmployee) => bornInAmericaEmployees.includes(ChineseEmployee)
);

console.log(ABCEmployees); // ["Mira"]

在這個版本中,可以發現中間的表達式(Line 6-8)沒有造成程式中的其他部分狀態被改變,無交互作用,無副作用發生。

例子二:let關鍵字

問題定義。 FP控老闆過分關心你這週side-project repo瀏覽總數。目前已知每天瀏覽數viewsPerDay,求七天瀏覽總數totalViews

如果要惹怒他,我推薦這樣寫:

// 可能會被FP老闆討厭的寫法
// imperative paradigm
const viewsPerDay = [324, 132, 532, 654, 544, 821, 732];

let totalViews = 0;

for (const view of viewsPerDay) {
    totalViews += view;
}

console.log(totalViews); // 3739

在這個例子中,FP控老闆討厭的點一樣有兩個:

  1. 這個例子把變數totalViews宣告在迴圈之外。
  2. 這個例子用let關鍵字初始化變數。

如果可以的話,請避免有重新賦值(reassigning)的行為。在大多數的情況中,我們希望以const關鍵字初始化變數並馬上賦值。

為了討他歡心,或許你可以改成這樣:

// 較受FP老闆喜歡的寫法
// declarative paradigm
const viewsPerDay = [324, 132, 532, 654, 544, 821, 732];

const totalViews = viewsPerDay.reduce((total, view) => total + view);

console.log(totalViews); // 3739

例子三:sort方法

問題定義。 基於瀏覽數viewsPerDay,這次FP控老闆想請知道排序後的結果sortedViewsPerDay

依據上面的經驗你可能會這樣寫:

// 可能會被FP老闆討厭的寫法
const viewsPerDay = [324, 132, 532, 654, 544, 821, 732];

const sortedViewsPerDay = viewsPerDay.sort();

console.log(viewsPerDay); // [132, 324, 532, 544, 654, 732, 821]
console.log(sortedViewsPerDay); // [132, 324, 532, 544, 654, 732, 821]

在這個例子中,要注意的是sort方法是in-place方法,會改變原本array狀態,進而違背FP的原則。

或許,我們可以使用Spread Operator複製原本的array,再進行排列。

// 較受FP老闆喜歡的寫法
const viewsPerDay = [324, 132, 532, 654, 544, 821, 732];

const sortedViewsPerDay = [...viewsPerDay].sort();

console.log(viewsPerDay); // [324, 132, 532, 654, 544, 821, 732]
console.log(sortedViewsPerDay); // [132, 324, 532, 544, 654, 732, 821]

這也太雷了吧!到底還有哪些方法會改變原本array狀態呢?

其實你早已了然於心:pushshiftunshiftpopreversesplicesort、以及fill,在FP中皆要慎用。

小練習

問題定義。 讓亂數決定,在未來十年內,何時會遇見真愛、升官、賺大錢、美夢成真。

同事寫了一個版本:

const events = ["true_love", "promotion", "fortune", "dreams_come_true"];
const answers = {};

const answersYears = events.reduce((newAns, event) => {
    newAns[event] = Math.floor(2022 + Math.random() * 10);
    return newAns;
}, answers);

console.log(answers); 
// {true_love: 2023, promotion: 2024, fortune: 2024, dreams_come_true: 2026}

如果你是我FP老闆,是否會生氣,為什麼?如果會,你會怎麼幫他?


上一篇
信仰:初見Funtional Programming
下一篇
摯友:Array(2/2)
系列文
被討厭的前端實務手冊|JS x TS x React18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言