[英]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.