唯有全然的了解,才有資格說愛或恨。
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控老闆討厭的點有兩個:
ABCEmployees
宣告在迴圈之外。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控老闆討厭的點一樣有兩個:
totalViews
宣告在迴圈之外。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狀態呢?
其實你早已了然於心:push
、shift
、unshift
、pop
、reverse
、splice
、sort
、以及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老闆,是否會生氣,為什麼?如果會,你會怎麼幫他?