Ramda 之 update()
栏目: JavaScript · 发布时间: 5年前
内容简介: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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。