點燈坊

失くすものさえない今が強くなるチャンスよ

使用 prop() 取得 Object 的 Property

Sam Xiao's Avatar 2020-02-18

map() 的 Callback 常需要常需要從 Object 取得 Property,可使用 Ramda 的 prop() 使 Callback 能 Point-free。

Imperative

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let f = k => arr => {
  let result = []

  for(let x of arr)
    result.push(x[k])

  return result
}

f('title')(data)  // ?

若我們只需要 array 指定 property,imperative 會使用 for loop 並使用 [] 取得指定 property。

prop001

ECMAScript

reduce()

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let f = k => arr => arr.reduce((a, x) => [...a, x[k]], [])

f('title')(data)  // ?

只要能使用 for loop,就能使用 reduce() 改寫。

prop007

map()

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let f = k => arr => arr.map(x => x[k])

f('title')(data)  // ?

可使用 ECMAScript 自帶的 map() 取代 for loop,並在 arrow function 內取得指定 property。

prop002

Ramda

import { prop, map } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let f = k => map(x => x[k])

f('title')(data)  // ?

可使用 Ramda 的 map() 取代,並使 arr argument point-free。

prop003

prop()

import { map } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let prop = k => obj => obj[k]

let f = k => map(prop(k))

f('title')(data)  // ?

若要使 map() 的 callback 也 point-free,可自行實作 prop() 取代 []

prop006

import { prop, map } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let f = v => map(prop(v))

f('title')(data)  // ?

Ramda 已經提供 prop() 可直接使用。

prop()
s -> {s: a} -> a | undefined
傳入 key 與 object,傳回 value

s:object 的 key

{s: a}:data 為 object

a | undefined:傳回 value,若找不到為 undefined

prop004

compose()

import { prop, map, compose } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let f = compose(map, prop)

f('title')(data)  // ?

也可使用 compose()map()prop() 組合起來。

prop005

Conclusion

  • prop() 會傳回 Ramda 所需要的 callback,只要傳入 object 的 property 名稱即可
  • FP 的 data 都會放在最後一個 argument,因此可輕鬆做 point-free

Reference

MDN, Array.prototype.reduce()
MDN, Array.prototype.map()
Ramda, map()
Ramda, prop()
Ramda, compose()