---
tags: Functional Programming
---
# DRY 第一哩路 - 抽象化
當我們把一段程式碼包成一個 function 時,其實就是在作抽象化,良好的抽象化可以讓 function 更有彈性,也更容易維護、使用,假設現在有一個需要過濾物件的 function:
```jsx
//資料
var taskArray = [
{
id: 1,
userId: 1,
userName: 'Jerry',
complete: false,
title: 'Write 《Think in FP》 serise article',
content: '...',
dueDate: '2020-05-31',
priority: 0,
},
...
];
```
如果需求是想過濾出已經完成的資料 `complete === true`
```jsx
//過濾 function
function filterTaskArray(taskArray) {
const result = [];
for (let i = 0; i < taskArray.length; i++) {
if (taskArray[i].complete) {
result.push(taskArray[i]);
}
}
return result;
}
```
這時 PM 又想新增一個過濾出某個特定的 userId,有可能就會變成下面這樣:
```jsx
function filterTaskArray(taskArray, { filterComplete = false, filterUserId = undefined } = {}) {
const result = [];
for (let i = 0; i < taskArray.length; i++) {
if (
(filterComplete && !taskArray[i].complete) ||
(filterUserId != null && taskArray[i].userId !== filterUserId)
) {
continue;
}
result.push(taskArray[i]);
}
return result;
}
```
使用方式變成這樣:
```jsx
const result = filterTaskArray(taskArray, {
filterComplete: true,
filterUserId: 1
});
```
可以知道,這樣的抽象是非常糟糕的,每次新增一個需求就需要多幾個條件,使用者會需要填入更多的參數,整個功能也會非常難讀懂。
所以當一個 function 可以過濾出一個 array 某些特定的元素時,需要抽象的事情只有一個 -- 過濾 Array,至於是過濾什麼條件就應該由外部的使用者決定!
這樣一來,就等於把部分邏輯交由外部的使用者決定,我們要做的只需要規定使用者傳一個 function 進來,並預期這個 function 會回傳某種值就可以了
```jsx
function filter(array, fn) { // function 改名為 filter,參數改名為 array
const result = [];
for (let i = 0; i < array.length; i++) {
if (fn(array[i])) { // 傳 array[i] 進去,並預期 fn(array[i]) 會回傳 Boolean。
result.push(array[i]);
}
}
return result;
}
```
使用方式就變成下面這樣:
```jsx
const result = filter(taskArray, item => item.complete && item.userId = 1)
```
## 總結
抽象做得好,其實彈性是非常大的,只要是 array 都可以使用,並且邏輯可以交由使用的人依據情況決定,也幾乎不再需要再修改這個 function!