實務上常遇到 API 回傳資料為 Nested Array,但卻要以 ,
隔開的 String 顯示,這種常見需求該如何實現呢 ?
Version
Ramda 0.27.1
join()
import { pipe, map, lensProp, over, join } from 'ramda'
let data = [
{ title: 'FP in JavaScript', authors: ['John', 'Kevin', 'Tom'] },
{ title: 'RxJS in Action', authors: ['Sam' , 'Jerry', 'Ray'] },
{ title: 'Speaking JavaScript', authors: ['May' , 'Mary', 'Jen'] },
]
pipe(
map(x => ({
...x,
authors: x.authors.join(',')
}))
)(data) // ?
第 3 行
let data = [
{ title: 'FP in JavaScript', authors: ['John', 'Kevin', 'Tom'] },
{ title: 'RxJS in Action', authors: ['Sam' , 'Jerry', 'Ray'] },
{ title: 'Speaking JavaScript', authors: ['May' , 'Mary', 'Jen'] },
]
authors
是以 Array 型態存在,但卻希望以 String 顯示。
第 9 行
pipe(
map(x => ({
...x,
authors: x.authors.join(',')
}))
)(data) // ?
使用 pipe()
組合出 IIFE:
map()
:新資料筆數與原筆數相同,因此使用map()
join()
:回傳仍是 Object,因此使用 arrow function 回傳 Object,authors
Array 使用Array.prototype.join(',')
轉成 String
Point-free
import { pipe, map, lensProp, over, join } from 'ramda'
let data = [
{ title: 'FP in JavaScript', authors: ['John', 'Kevin', 'Tom'] },
{ title: 'RxJS in Action', authors: ['Sam' , 'Jerry', 'Ray'] },
{ title: 'Speaking JavaScript', authors: ['May' , 'Mary', 'Jen'] },
]
pipe(
map(over(lensProp('authors'), join(',')))
)(data) // ?
第 9 行
pipe(
map(over(lensProp('authors'), join(',')))
)(data) // ?
整個關鍵在於 join(',')
將 authors
Array 轉成 String,但 join(',')
是 function 而非 value,有幾個 function 可考慮:
assoc()
:可直接修改authors
Array,但必須提供 value,因此並不適合set()
:可直接修改authors
Array,但必須提供 value,因此並不適合over()
:可直接修改authors
Array,但必須提供 function,因此可直接使用join(',')
唯 over()
需搭配 Lens,因此使用 lensProp('authors')
先建立 Lens,如此 map()
的 callback 可完全 Point-free。
Conclusion
- 很多人並不熟悉 Lens,但偏偏
over()
這個可提供 function 修改 property 的 function 僅接受 Lens,因此懂不懂 Lens 成為本文關鍵