【问题标题】:Performing function on object and then manipulating the object in Ramda在对象上执行功能,然后在 Ramda 中操作对象
【发布时间】:2020-10-03 05:40:21
【问题描述】:

我正在为一点点 ramda 逻辑而苦苦挣扎,我觉得我几乎掌握了它,但我的大脑今天无法正常工作。

我有一个对象:

const thing = {
  'name': 'thing',
  'value': 1000.0987654321,
  'valueAsString': "1000.0987654321",
  'otherThings': { 'blah': 'blah' },
}

我想从事物中提取“名称”和“值”,但我想在返回新对象之前对值进行四舍五入。

我知道要提取名称和值,我可以使用 pick:R.pick(['name', 'value']) 并执行舍入函数,我可以采用现有的舍入函数:

const roundTo9Dp = (n) => Number((n).toFixed(9))

并将其应用于我的对象,如下所示:R.compose(roundTo9Dp, R.prop('value'))

这两个操作独立工作:

const picker = R.pick(['name', 'value'])
picker(thing) // => {"name": "thing", "value": 1000.0987654321}

const rounded = R.compose(roundTo9Dp, R.prop('value'))
rounded(thing) // => 1000.098765432

当我加入他们时,我正在挣扎。就好像他们在不同层次上操作“事物”,而我只是在努力解开它们。

R.compose(picker, R.assoc('value', rounded))(thing) // Incorrect
picker(R.compose(R.assoc('value'), rounded)(thing)(thing)) // works, but is hideous

【问题讨论】:

    标签: javascript functional-programming ramda.js


    【解决方案1】:

    您可以通过多种方式使用 Ramda 来做到这一点。以下是一些:

    const roundTo9Dp = (n) => Number((n).toFixed(9))
    
    const foo1 = applySpec({
      name: prop('name'),
      value: compose(roundTo9Dp, prop('value'))
    })
    
    const foo2 = pipe(
      pick (['name', 'value']),
      over (lensProp ('value'), roundTo9Dp)
    )
    
    const rounded = R.compose(roundTo9Dp, R.prop('value'))
    const foo3 = pipe(
      pick (['name', 'value']),
      chain(assoc('value'), rounded)
    )
    
    const foo4 = pipe(
      props (['name', 'value']),
      zipWith (call, [identity, roundTo9Dp]),
      zipObj (['name', 'value'])
    )
    
    const thing = {name: 'thing', value: 1000.0987654321, valueAsString: "1000.0987654321", otherThings: {blah: 'blah'}}
    
    console .log ('foo1:', foo1 (thing))
    console .log ('foo2:', foo2 (thing))
    console .log ('foo3:', foo3 (thing))
    console .log ('foo4:', foo4 (thing))
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
    <script> const {applySpec, prop, compose, pipe, pick, over, lensProp, chain, assoc, props, zipWith, call, identity, zipObj} = R </script>

    如果我们尝试,我们可以想出更多。 foo3 可能最接近您正在努力解决的问题。 chain 应用于函数时的工作方式类似于 chain (f, g) (x) //=&gt; f (g (x)) (x),这将避免您的版本中丑陋的 (thing) (thing)。这个版本可能会教你一些关于FantasyLand 类型类的世界。 foo1 使用 Ramda 更方便的对象操作函数之一,applySpecfoo2使用lensPropover,可以带你进入迷人的镜头世界。 foo4,虽然可能不推荐,但展示了 zipWithzipObj,用于组合列表的函数。

    但除非这是关于学习 Ramda,否则我不建议使用这些,因为这很简单,无需现代 JS 中的任何库即可:

    const foo = ({name, value}) => 
      ({name, value: roundTo9Dp(value)})
    

    我是 Ramda 的创始人之一,我仍然是忠实粉丝。但是我认为它是一个库,当它使代码更清晰和更易于维护时可以使用它。在这里,最简单的版本不需要它。

    【讨论】:

    • 感谢您的出色回答,它给了我很多机会,尝试和学习。
    • 最初的问题是对我试图解决的问题的刻意简化,但我也和你一样热衷于选择一个有利于更简洁和更可维护代码的实用解决方案,所以我一定会在实际提交 VCS 时提醒自己,特别是因为我编写的原始代码看起来与非 ramda 解决方案非常相似。
    • @purpletonic:我建议,如果您有许多属性要修改,那么您可能希望将多个lens 调用与上面的over (lensProp ('value'), roundTo9Dp) 类似。或调查evolve。但是,只有当输出属性与输入属性具有相同的名称并且它仅取决于该输入值时,这两种方法中的任何一种才有效。如果您有更复杂的场景,那么applySpec 会稍微不那么方便,但功能要强大得多。
    猜你喜欢
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多