Ramda 之 update()
栏目: JavaScript · 发布时间: 6年前
内容简介:Ramda 提供了可再使用VS Code 1.31.1
Ramda 提供了 update() ,可直接以新的 Object 取代原有 Array 內的 Object,唯必須在第一個參數提供欲更新的 Array Index,因此必須先使用 findIndex() 先找到 Index。
可再使用 compose() 與 useWith() 替 findIndex() 加以重構。
Version
VS Code 1.31.1
Quokka 1.0.136
Ramda 0.26.1
Update() 與 FindIndex()
import { findIndex, propEq, update, prop } from 'ramda'
const data = [
{ id: 1, title: 'Impatient JavaScript', year: 2018 },
{ id: 2, title: 'RxJS in Action', year: 2017 },
{ id: 3, title: 'Speaking JavaScript', year: 2014 }
]
const editItem = { id: 1, title: 'JavaScript for Kids', year: 2019 }
const updateBook = (item, data) => update(
findIndex(x => x.id === item.id, data),
item,
data
)
const result = updateBook(editItem, data)
console.dir(result)
data 為原始資料, editItem 則為修改過後的資料,欲將整個 editItem 取代原本 id 為 1 的 object。
定義出 updateBook() ,傳入欲取代的 item 與原始資料 data 即可,底層使用的是 Ramda 的 update() 。
update()
Number → a → [a] → [a]
將 object 取代 array 內指定 index 的 object
Number :array 的 index
a :欲取代的 object 或任意型別的值
[a] :data 為 array
[a] :取代後新的 array
第一個參數 Number 是關鍵,必須提供 array 的 index,但 index 如何來呢 ? 可靠 Ramda 的 findIndex() 求得。
findIndex()
(a → Boolean) → [a] → Number
由 predicate function 求得符合條件的 array index
(a -> Boolean) :Predicate function,指定判斷條件, true 則傳回 index
[a] :data 為 array
Number :傳回 array 的 index
12 行
findIndex(x => x.id === item.id, data),
Predicate function 為 array 的 x.id 必須與 editItem.id 相等。
propEq()
import { findIndex, propEq, update, prop } from 'ramda'
const data = [
{ id: 1, title: 'Impatient JavaScript', year: 2018 },
{ id: 2, title: 'RxJS in Action', year: 2017 },
{ id: 3, title: 'Speaking JavaScript', year: 2014 },
]
const editItem = { id: 1, title: 'JavaScript for Kids', year: 2019 }
const updateBook = (item, data) => update(
findIndex(propEq('id', prop('id', item)), data),
item,
data
)
const result = updateBook(editItem, data);
console.dir(result)
原本 12 行
findIndex(x => x.id === item.id, data),
的 predicate function 並非 Point-free,可以改用 Ramda 的 propEq() 加以優化。
findIndex(propEq('id', prop('id', item)), data),
propEq()
String → a → Object → Boolean
比對 object 的 property 與 value 是否相等
String :object 的 property
a :要找的資料
Object :data 為 object
Boolean :若找到傳回 true ,找不到傳回 false
由於 proEq() 的 currying 特性,只提供前兩個參數,剛好回傳 Object -> Boolean function,剛好就是 findIndex() 所要的 predicate function
至於 propEq() 的第二個參數 a ,就是 item.id ,可使用 Ramda 的 prop() 。
prop()
s -> {s: a} -> a | undefined
傳入 key 與 object,傳回 value
Compose()
import { findIndex, propEq, update, prop, compose } from 'ramda'
const data = [
{ id: 1, title: 'Impatient JavaScript', year: 2018 },
{ id: 2, title: 'RxJS in Action', year: 2017 },
{ id: 3, title: 'Speaking JavaScript', year: 2014 },
]
const editItem = { id: 1, title: 'JavaScript for Kids', year: 2019 }
const keyEq = key => compose(
propEq(key),
prop(key)
)
const updateBook = (item, data) => update(
findIndex(keyEq('id')(item), data),
item,
data
)
const result = updateBook(editItem, data);
console.dir(result)
原本 12 行
propEq('id', prop('id', item))
findIndex() 的 predicate function,是先執行 prop() ,再將結果傳給 propEq() 執行,其實就是 prop() 與 propEq() 兩個 function 的組合。
11 行
const keyEq = key => compose( propEq(key), prop(key) )
因此可將 prop() 與 propEq() 組合成新的 keyEq() ,
16 行
const updateBook = (item, data) => update(
findIndex(keyEq('id')(item), data),
item,
data
)
findIndex() 則改用新的 keyEq() ,語意更為清楚。
UseWith()
import { findIndex, propEq, update, prop, compose, useWith, identity } from 'ramda'
const data = [
{ id: 1, title: 'Impatient JavaScript', year: 2018 },
{ id: 2, title: 'RxJS in Action', year: 2017 },
{ id: 3, title: 'Speaking JavaScript', year: 2014 },
]
const editItem = { id: 1, title: 'JavaScript for Kids', year: 2019 }
const keyEq = key => compose(
propEq(key),
prop(key)
)
const findIndexByKey = key => useWith(
findIndex,
[
keyEq(key),
identity
]
)
const updateBook = (item, data) => update(
findIndexByKey('id')(item, data),
item,
data
)
const result = updateBook(editItem, data);
console.dir(result)
原本 17 行
findIndex(keyEq('id')(item), data)
目前 id 直接 hard code,事實上可將 id 抽成 parameter,則重複使用性更高。
注意 findIndex() 第一個參數用到 item ,第二個參數用到 data ,剛好就是 Ramda useWith() 格式,可改用 useWith() 使新的 findIndexByKey() Point-free。
16 行
const findIndexByKey = key => useWith(
findIndex,
[
keyEq(key),
identity
]
)
改用 useWith() 之後,只剩下 key 一個參數, item 與 data 被 useWith() Point-free 了。
key 因為是 Higher Order Function 的參數,所以一定要提供,我們能做的是將 data 部分 Point-free
24 行
const updateBook = (item, data) => update(
findIndexByKey('id')(item, data),
item,
data
)
抽出 findIndexByKey() 之後, updateBook() 的可讀性更高了,且 findIndexByKey() 將來還可以重複使用。
Conclusion
-
finIndex()的 predicate function 可搭配propEq()產生 - 雖然看似產生了
keyEq()與findIndexByKey()兩個小 function,行數變多了,但事實上這兩個小 function 重複使用度極高,可以重構到 helper function 的 module,本質上updateBook()更為精簡,且可讀性更高 -
compose()與useWith()在重構過程經常使用,可藉此產生小 function 並且 Point-free
Reference
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。