Ramda 之 update()

栏目: JavaScript · 发布时间: 4年前

内容简介: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 取代原本 id1 的 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 相等。

Ramda 之 update()

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

Ramda 之 update()

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() ,語意更為清楚。

Ramda 之 update()

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 一個參數, itemdatauseWith() Point-free 了。

key 因為是 Higher Order Function 的參數,所以一定要提供,我們能做的是將 data 部分 Point-free

24 行

const updateBook = (item, data) => update(
  findIndexByKey('id')(item, data),
  item, 
  data
)

抽出 findIndexByKey() 之後, updateBook() 的可讀性更高了,且 findIndexByKey() 將來還可以重複使用。

Ramda 之 update()

Conclusion

  • finIndex() 的 predicate function 可搭配 propEq() 產生
  • 雖然看似產生了 keyEq()findIndexByKey() 兩個小 function,行數變多了,但事實上這兩個小 function 重複使用度極高,可以重構到 helper function 的 module,本質上 updateBook() 更為精簡,且可讀性更高
  • compose()useWith() 在重構過程經常使用,可藉此產生小 function 並且 Point-free

Reference

Ramda , update()

Ramda , findIndex()

Ramda , propEq()

Ramda , prop()

Ramda , compose()

Ramda , useWith()


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

你的品牌,价值千万

你的品牌,价值千万

温迪 / 人民邮电出版社 / 2018-7-1 / 49.00元

“大道无术,万法归心。” 不管是互联网、社交媒体,还是 AI 怎样让人眼花缭乱。从“真心”出发塑造的个人品牌,都将带你从容面对任何一种变化的冲击。现代生活变得越来越透明,如果你不懂得如何真实、精准地定位和呈现自己,你的个人品牌在 碎片信息中被误解、被曲解就是一种必然。 本书分四步引导你剖析自己、发现自我,构建可持续的品牌生态系统,策划品牌战略,提升个人呈现力,并在最后带你勾画出一幅完整的个人......一起来看看 《你的品牌,价值千万》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具