繁体   English   中英

如何用 Ramda 模仿 lodash.set

[英]How to imitate lodash.set with Ramda

我正在学习 Ramda,但我很困惑。 我想创建一个类似于 lodash.set 函数的 set 函数。 但是,当我在对象中存在的路径上尝试以下操作时,它似乎按预期工作,但是当我使用它来创建新路径时,它会添加这个奇怪的数组。

const R = require('ramda')

const set = (object, path, value) => R.set(R.lensPath(path), value, object);

const foo = {
  moo: {
    goo: 'goo'
  }
}


set(foo, ['moo', 'goo', 'boo'], 'roo'); // { moo: { goo: { '0': 'g', '1': 'o', '2': 'o', boo: 'roo' } } }

所以结果是: // { moo: { goo: { '0': 'g', '1': 'o', '2': 'o', boo: 'roo' } } }

当我期望它是: // { moo: { goo: { boo: 'roo' } } }

为什么按索引添加这些字符? 如何使用 Ramda 完成 lodash.set 功能?

这似乎是不需要的行为。 为什么有人希望 Ramda 强制字符串?

我认为这是一个不同的问题。 foo.moo.goo是一个字符串时,您正在编写的代码应该做一些模糊地等同于foo.moo.goo.boo = 'roo' foo.moo.goo 这当然会引发错误,例如Cannot create property 'boo' on string 'goo'

Lodash 的回答是这样的:“哦,你一定是说foo.moo.goo = {boo: 'roo'} 这是一个完全合理的猜测。 但这是一个猜测。 图书馆应该抛出像上面那样的错误吗? 这可能是合乎逻辑的做法。

Ramda(免责声明:我是它的作者之一)做出了不同的选择。 它假定您的意思是您所说的。 您想要更新foo.moo goo属性, foo.moo是将其boo属性设置为'roo' 然后它这样做。 但是,当它更新这样的属性时,与其他任何地方一样,它不会改变您的原始数据,而是为您构建一个新的输出,复制旧对象的属性,除了这个新路径,它适当地设置。 那么,你的旧对象( 'goo' )有三个属性, {0: 'g'} {1: 'o'}{2: 'o'}这Ramda的assocPath (公共函数也被用于lensPath完成这项工作)然后与您的{boo: 'roo'}组合成一个对象。

但我在这里夸大其词。 Ramda 从未真正做出过这个选择。 这只是实施中失败的原因。 assocPath只知道两种类型:数组和对象。 它只知道如何重建这些类型。 实际上它可以作为数组和其他人使用。 由于您的foo.moo不是数组,因此它将其视为对象。

如果你希望看到这种行为发生改变,一个新的 issue或者更好的pull request会得到公平的听证会。 我可以向你保证那个。

但我预计会有很多阻力。

Ramda 的哲学与 lodash 的哲学截然不同。 lodash 强调灵活性。 例如, set允许您将路径写为数组或字符串,其中有两个示例

_.set(object, 'a[0].b.c', 4);

_.set(object, ['x', '0', 'y', 'z'], 5);

并且许多函数都有可选参数。 它可以自由地改变提供给它的数据。 它旨在“为尽可能多的开发人员提供高质量的实用方法,重点是一致性、兼容性、定制化和性能”。 正如它的创始人曾经说过的那样

相比之下,Ramda 不太担心灵活性。 Ramda 的一个更重要的目标是简单性 它的 API 没有可选参数。 当它允许一个参数有多种类型时,只是因为它们共享更高的抽象。 提供给assocPath的路径是一个数组,并且只是一个数组; 它通过注意每个路径元素是字符串还是整数来处理对象与数组。 当然,Ramda 永远不会改变您的输入数据。

Ramda 也对手持设备不感兴趣。 哲学通常是垃圾进,垃圾出之一。 这个案子似乎进入了那个领域。 Ramda 会心甘情愿地将{moo: {goo: 'goo'}}转换为{moo: {goo: {boo: 'roo'}}} 但是你必须更明确地告诉它这样做: assoc(['moo', 'goo'], {boo: 'roo'})

因此,改变这一点的请求可能很难推销……但这是一群友好的人。 如果您认为这很重要,请随时提出。

我觉得我只需要从 lodash 导入set函数来防止意外行为。

但请记住,行为是多么不同。 最大的区别是 lodash 正在改变它的输入,而 Ramda 不会这样做。 他们对要增强哪些值和替换哪些值有不同的想法(如当前示例中所示)。当然,他们的签名是不同的。 它们在数组索引方面有不同的行为。 (例如,我想不出在 lodash 的set中添加一个字符串键为 '0' 的对象的方法。当你调用类似assocPath(['grid', 'width'], newVal, myObj) ,而 lodash 很乐意改变内部的 Rectangle 对象。)

换句话说,它们是不同的行为,为不同的目的而设计。 如果 lodash 的行为是您想要的,请务必包含它。 但是,如果您在大部分实用程序工作中都使用 Ramda,请注意它们的理念有何不同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM