map()
+ pick()
是實務上常用組合,可重構成 project()
更為優雅。
Version
macOS Catalina 10.15.4
VS Code 1.44.0
Quokka 1.0.285
Ramda 0.27.0
Imperative
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' }
]
let f = a => {
let result = []
for (let x of a)
result.push({ title: x.title, price: x.price })
return result
}
f(data) // ?
第 1 行
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' }
]
我們只想擷取 title
與 price
兩個 property 的 array。
第 7 行
let f = a => {
let result = []
for (let x of a)
result.push({ title: x.title, price: x.price })
return result
}
Imperative 會先建立 result
empty array,使用 for
loop 對 data 一筆一筆處理,然後只將部分 property push 進 result
,最後回傳 result
array。
reduce()
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' }
]
let f = a => a.reduce((a, x) => ([
...a,
{ title: x.title, price: x.price }
]), [])
f(data) // ?
只要能使用 for
loop,就能使用 reduce()
改寫。
map()
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' },
]
let f = a => a.map(x => ({ title: x.title, price: x.price }))
f(data) // ?
ECMAScript 可使用 map()
只將 title
與 price
兩 property 回傳。
Ramda
import { map } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' }
]
let f = map(x => ({ title: x.title, price: x.price }))
f(data) // ?
可使用 Ramda 的 map()
使 f()
能 point-free。
pick()
import { map, pick } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' }
]
let f = map(pick(['title', 'price']))
f(data) // ?
可使用 Ramda 的 pick()
使 map()
的 callback 也 point-free。
project()
import { project } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100, category: 'FP' },
{ title: 'RxJS in Action', price: 200, category: 'FRP' },
{ title: 'Speaking JavaScript', price: 300, category: 'JS' }
]
let f = project(['title', 'price'])
f(data) // ?
Ramda 還另外提供了 project
,相當於 map()
與 pick()
組合。
project()
[k] → [{k: v}] → [{k: v}]
只回傳 array 中 object 的部分 property
[k]
:部分 property 以 array 提供
[{k: v}]
:data 為 object array
[{k: v}]
:回傳部分 property 的 object array
Conclusion
- 一開始可能沒想到
project()
,但看到map()
+pick()
pattern 別忘了重構成project()