如何用Ramda模仿lodash.set
How to imitate lodash.set with Ramda
正在学习Ramda,一头雾水。我想创建一个类似于 lodash.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 功能?
It seems like unwanted behavior. Why would anyone want Ramda to coerce the string?
我认为这是一个不同的问题。当 foo.moo.goo
是一个字符串时,您正在编写的代码应该做一些模糊地等同于 foo.moo.goo.boo = 'roo'
的事情。那当然会引发错误,例如 Cannot create property 'boo' on string 'goo'
.
Lodash 通过类似 "Oh, you must have meant foo.moo.goo = {boo: 'roo'}
." 的回答来回答这个问题,这是一个完全合理的猜测。但这是一个猜测。图书馆是否应该抛出上述错误?这可能是最合乎逻辑的事情。
Ramda(免责声明:我是其作者之一)做出了不同的选择。它假设你是认真的。您想要更新 foo.moo
的 goo
属性,方法是将其 boo
属性 设置为 'roo'
。然后它会这样做。但是,当它像这样更新 属性 时,与其他地方一样,它不会改变您的原始数据,而是为您构建一个新的输出,复制旧对象的属性,除了它适当设置的这个新路径.那么,您的旧对象 ('goo'
) 具有三个属性,{0: 'g'}
、{1: 'o'}
和 {2: 'o'}
,其中 Ramda 的 assocPath
(public 函数lensPath
也使用它来完成这项工作)然后与您的 {boo: 'roo'}
.
组合成一个对象
但我在这里夸大了。 Ramda 从未真正做出过这个选择。这只是实施中出现的问题。 assocPath
只知道两种类型:数组和对象。它只知道如何重建这些类型。实际上它可以用作数组和其他。由于您的 foo.moo
不是数组,因此它会将其视为对象。
如果您希望改变这种行为,new issue, or even better a pull request 会得到公平的听证会。我可以向你保证。
但我预计会遇到很多阻力。
Ramda 的哲学与 lodash 的哲学有很大不同。 lodash 强调灵活性。例如,set
允许您将路径写为数组或字符串,其两个示例
_.set(object, 'a[0].b.c', 4);
_.set(object, ['x', '0', 'y', 'z'], 5);
而且很多函数都有可选参数。它自由地改变提供给它的数据。它的设计目标是 "providing quality utility methods to as many devs as possible with a focus on consistency, compatibility, customization, and performance." 作为其创始人 once said。
相比之下,Ramda 不太担心灵活性。 Ramda 的一个更重要的目标是简单。它的 API 没有可选参数。当它允许一个参数有多种类型时,这只是因为它们共享更高的抽象。提供给 assocPath
的路径是一个数组,而且只是一个数组;它通过注意每个路径元素是字符串还是整数来处理对象与数组。当然,Ramda 永远不会改变您的输入数据。
Ramda 也对手持不感兴趣。这种理念通常是垃圾进,垃圾出。这个案子似乎进入了那个领域。 Ramda 会自愿将 {moo: {goo: 'goo'}}
转换为 {moo: {goo: {boo: 'roo'}}}
。但是你必须更明确地告诉它这样做:assoc(['moo', 'goo'], {boo: 'roo'})
。
因此,更改此设置的请求可能很难说服...但这是一群友好的人。如果您认为重要,请随时提出来。
I feel like I just have to import set
function from lodash to prevent unexpected behavior.
但请记住,行为有多么不同。最大的区别是 lodash 正在改变它的输入,而 Ramda 不会这样做。他们对哪些价值要增强,哪些价值要取代(如当前示例)有不同的想法。当然,他们的签名是不同的。它们在数组索引方面有不同的行为。 (例如,我想不出在 lodash 的 set
中添加一个带有字符串键 '0' 的对象的方法。当你调用 assocPath(['grid', 'width'], newVal, myObj)
之类的东西时,Ramda 当然不会包含一个构造的矩形,而 lodash 会很乐意改变内部 Rectangle 对象。)
换句话说,它们是不同的行为,为不同的目的而设计。如果 lodash 的行为是您想要的,请务必包含它。但是,如果您将 Ramda 用于大部分实用程序工作,请注意它们的理念有何不同。
正在学习Ramda,一头雾水。我想创建一个类似于 lodash.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 功能?
It seems like unwanted behavior. Why would anyone want Ramda to coerce the string?
我认为这是一个不同的问题。当 foo.moo.goo
是一个字符串时,您正在编写的代码应该做一些模糊地等同于 foo.moo.goo.boo = 'roo'
的事情。那当然会引发错误,例如 Cannot create property 'boo' on string 'goo'
.
Lodash 通过类似 "Oh, you must have meant foo.moo.goo = {boo: 'roo'}
." 的回答来回答这个问题,这是一个完全合理的猜测。但这是一个猜测。图书馆是否应该抛出上述错误?这可能是最合乎逻辑的事情。
Ramda(免责声明:我是其作者之一)做出了不同的选择。它假设你是认真的。您想要更新 foo.moo
的 goo
属性,方法是将其 boo
属性 设置为 'roo'
。然后它会这样做。但是,当它像这样更新 属性 时,与其他地方一样,它不会改变您的原始数据,而是为您构建一个新的输出,复制旧对象的属性,除了它适当设置的这个新路径.那么,您的旧对象 ('goo'
) 具有三个属性,{0: 'g'}
、{1: 'o'}
和 {2: 'o'}
,其中 Ramda 的 assocPath
(public 函数lensPath
也使用它来完成这项工作)然后与您的 {boo: 'roo'}
.
但我在这里夸大了。 Ramda 从未真正做出过这个选择。这只是实施中出现的问题。 assocPath
只知道两种类型:数组和对象。它只知道如何重建这些类型。实际上它可以用作数组和其他。由于您的 foo.moo
不是数组,因此它会将其视为对象。
如果您希望改变这种行为,new issue, or even better a pull request 会得到公平的听证会。我可以向你保证。
但我预计会遇到很多阻力。
Ramda 的哲学与 lodash 的哲学有很大不同。 lodash 强调灵活性。例如,set
允许您将路径写为数组或字符串,其两个示例
_.set(object, 'a[0].b.c', 4);
_.set(object, ['x', '0', 'y', 'z'], 5);
而且很多函数都有可选参数。它自由地改变提供给它的数据。它的设计目标是 "providing quality utility methods to as many devs as possible with a focus on consistency, compatibility, customization, and performance." 作为其创始人 once said。
相比之下,Ramda 不太担心灵活性。 Ramda 的一个更重要的目标是简单。它的 API 没有可选参数。当它允许一个参数有多种类型时,这只是因为它们共享更高的抽象。提供给 assocPath
的路径是一个数组,而且只是一个数组;它通过注意每个路径元素是字符串还是整数来处理对象与数组。当然,Ramda 永远不会改变您的输入数据。
Ramda 也对手持不感兴趣。这种理念通常是垃圾进,垃圾出。这个案子似乎进入了那个领域。 Ramda 会自愿将 {moo: {goo: 'goo'}}
转换为 {moo: {goo: {boo: 'roo'}}}
。但是你必须更明确地告诉它这样做:assoc(['moo', 'goo'], {boo: 'roo'})
。
因此,更改此设置的请求可能很难说服...但这是一群友好的人。如果您认为重要,请随时提出来。
I feel like I just have to import
set
function from lodash to prevent unexpected behavior.
但请记住,行为有多么不同。最大的区别是 lodash 正在改变它的输入,而 Ramda 不会这样做。他们对哪些价值要增强,哪些价值要取代(如当前示例)有不同的想法。当然,他们的签名是不同的。它们在数组索引方面有不同的行为。 (例如,我想不出在 lodash 的 set
中添加一个带有字符串键 '0' 的对象的方法。当你调用 assocPath(['grid', 'width'], newVal, myObj)
之类的东西时,Ramda 当然不会包含一个构造的矩形,而 lodash 会很乐意改变内部 Rectangle 对象。)
换句话说,它们是不同的行为,为不同的目的而设计。如果 lodash 的行为是您想要的,请务必包含它。但是,如果您将 Ramda 用于大部分实用程序工作,请注意它们的理念有何不同。