reduce()
為 FP 代表性 Function,很多人覺得 redurce()
沒有 Imperative 的 for
Loop 直覺,因而避而遠之,事實上只是沒用對 reduce()
而已 。
Version
macOS Catalina 10.15.2
VS Code 1.40.2
Quokka 1.0.259
Ramda 0.26.1
Imperative
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let fn = val => arr => {
let result = 0
for(let x of arr) {
if (x.title.includes(val))
result += x.price
}
return result
}
fn('JavaScript')(data) // ?
若我們想找出所有 title
包含 JavaScript
字眼的書籍的 price
總和。
Imperative 會在 for
loop 內使用 if
判斷 title
是否包含 JavaScript
,若包含則加總 price
,最後回傳結果。
Wrong Way
import { reduce } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let fn = val => reduce((a, x) => {
if (x.title.includes(val))
return a + x.price
else
return a
}, 0)
fn('JavaScript')(data) // ?
很多人會直接將 for
loop 的邏輯搬進 reduce()
內,結果雖然正確,但這並不是 reduce()
最佳用法。
Right Way
import { map, filter, reduce, pipe } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let fn = val => pipe(
filter(x => x.title.includes(val)),
map(x => x.price),
reduce((a, x) => a + x, 0)
)
fn('JavaScript')(data) // ?
FP 精神簡單來說就是:將問題最小化各個擊破,再加以組合
。
可將問題拆成 3 個步驟:
- 使用
filter()
找出title
為JavaScript
書籍 - 使用
map()
找出所有書籍的price
- 最後將
price
加總
最後一個步驟因為不知道用什麼 function,只好用 reduce()
實現。
reduce()
正確用法並不是將一個大大 function 放進reduce()
,而是先拆解問題以既有 function 解決,若仍無法處理才會使用reduce()
,最後再組合所有 function,也就是reduce()
不該搭配一個大大 function
import { map, filter, pipe, sum } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let fn = val => pipe(
filter(x => x.title.includes(val)),
map(x => x.price),
sum
)
fn('JavaScript')(data) // ?
隨著經驗累積,可能會發現有其他 function 能解決問題,或者可自行用 reduce()
建立新 function,此時可用該 function 取代 reduce()
。
Conclusion
reduce()
應該只用來處裡單純一件事情,因此都搭配小 function,若reduce()
搭配大 function,則表示該 function 一定能再拆解使用小 function 處理- 應該盡量先使用既有 function 解決問題,直到無法處理才會使用
reduce()
,實務上使用reduce()
機會沒這麼大,因為如 Ramda、Crocks 都已經累積足夠 function 可用,reduce()
只用來處理特殊部分,最後再組合所有 function,或者由reduce()
建立新的 function,供日後組合使用