简体   繁体   English

如何用 Ramda 模仿 lodash.set

[英]How to imitate lodash.set with Ramda

I am learning Ramda and I am confused.我正在学习 Ramda,但我很困惑。 I want to make a set function that works similar to the lodash.set function.我想创建一个类似于 lodash.set 函数的 set 函数。 However when I try the following on an path that exists in the object, it seems to work as intended, but when I use it to create a new path, it adds this weird array.但是,当我在对象中存在的路径上尝试以下操作时,它似乎按预期工作,但是当我使用它来创建新路径时,它会添加这个奇怪的数组。

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' } } }

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

When I expected it to be: // { moo: { goo: { boo: 'roo' } } }当我期望它是: // { moo: { goo: { boo: 'roo' } } }

Why does it add these characters by index?为什么按索引添加这些字符? How do I accomplish a lodash.set function with Ramda?如何使用 Ramda 完成 lodash.set 功能?

It seems like unwanted behavior.这似乎是不需要的行为。 Why would anyone want Ramda to coerce the string?为什么有人希望 Ramda 强制字符串?

I think of it as a different question.我认为这是一个不同的问题。 You're writing code that is supposed to do something vaguely equivalent to foo.moo.goo.boo = 'roo' , when foo.moo.goo is a string.foo.moo.goo是一个字符串时,您正在编写的代码应该做一些模糊地等同于foo.moo.goo.boo = 'roo' foo.moo.goo That would of course throw an error such as Cannot create property 'boo' on string 'goo' .这当然会引发错误,例如Cannot create property 'boo' on string 'goo'

Lodash answers this by saying something like "Oh, you must have meant foo.moo.goo = {boo: 'roo'} ." Lodash 的回答是这样的:“哦,你一定是说foo.moo.goo = {boo: 'roo'} That's a perfectly reasonable guess.这是一个完全合理的猜测。 But it's a guess.但这是一个猜测。 Should the library instead have thrown an error like the above?图书馆应该抛出像上面那样的错误吗? That would probably be the most logical thing to do.这可能是合乎逻辑的做法。

Ramda (disclaimer: I'm one of its authors) makes a different choice. Ramda(免责声明:我是它的作者之一)做出了不同的选择。 It assumes that you meant what you said.它假定您的意思是您所说的。 You wanted to goo property of foo.moo to be updated, by setting its boo property to 'roo' .您想要更新foo.moo goo属性, foo.moo是将其boo属性设置为'roo' It then does so.然后它这样做。 When it updates a property like this, though, as everywhere else, it does not mutate your original data, but builds you a new output, copying the properties of the old object except for this new path, which it sets appropriately.但是,当它更新这样的属性时,与其他任何地方一样,它不会改变您的原始数据,而是为您构建一个新的输出,复制旧对象的属性,除了这个新路径,它适当地设置。 Well, your old object ( 'goo' ) has three properties, {0: 'g'} , {1: 'o'} , and {2: 'o'} , which Ramda's assocPath (the public function also used by lensPath which does this job) then combines into a single object along with your {boo: 'roo'} .那么,你的旧对象( 'goo' )有三个属性, {0: 'g'} {1: 'o'}{2: 'o'}这Ramda的assocPath (公共函数也被用于lensPath完成这项工作)然后与您的{boo: 'roo'}组合成一个对象。

But I exaggerate here.但我在这里夸大其词。 Ramda never really made this choice. Ramda 从未真正做出过这个选择。 It's simply what fell out of the implementation.这只是实施中失败的原因。 assocPath knows about only two types: arrays and objects. assocPath只知道两种类型:数组和对象。 It knows how to reconstruct these types only.它只知道如何重建这些类型。 And really it works as arrays and others.实际上它可以作为数组和其他人使用。 Since your foo.moo is not an array, it treats it as an object.由于您的foo.moo不是数组,因此它将其视为对象。

If you would like to see this behavior changed, a new issue , or even better a pull request would receive a fair hearing.如果你希望看到这种行为发生改变,一个新的 issue或者更好的pull request会得到公平的听证会。 I can promise you that.我可以向你保证那个。

But I would expect a lot of pushback.但我预计会有很多阻力。

Ramda's philosophy is significantly different from that of lodash. Ramda 的哲学与 lodash 的哲学截然不同。 lodash emphasizes flexibility. lodash 强调灵活性。 set , for instance, allows you to write paths as arrays or strings, with its two examples of例如, set允许您将路径写为数组或字符串,其中有两个示例

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

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

and many functions have optional parameters.并且许多函数都有可选参数。 It freely mutates data supplied to it.它可以自由地改变提供给它的数据。 It is designed to be about "providing quality utility methods to as many devs as possible with a focus on consistency, compatibility, customization, and performance."它旨在“为尽可能多的开发人员提供高质量的实用方法,重点是一致性、兼容性、定制化和性能”。 as its founderonce said .正如它的创始人曾经说过的那样

Ramda, in contrast, is much less worried about flexibility.相比之下,Ramda 不太担心灵活性。 A much more important goal for Ramda is simplicity . Ramda 的一个更重要的目标是简单性 Its API has no optional parameters.它的 API 没有可选参数。 When it allows multiple types for an argument, it is only because there is a higher abstraction that they share.当它允许一个参数有多种类型时,只是因为它们共享更高的抽象。 The path supplied to assocPath is an array, and only an array;提供给assocPath的路径是一个数组,并且只是一个数组; it handles objects versus arrays by noting whether each path element is a string or an integer.它通过注意每个路径元素是字符串还是整数来处理对象与数组。 And of course Ramda never mutates your input data.当然,Ramda 永远不会改变您的输入数据。

Ramda also is not interested in hand-holding. Ramda 也对手持设备不感兴趣。 The philosophy is often one of garbage in, garbage out.哲学通常是垃圾进,垃圾出之一。 And this case seems to edge into that territory.这个案子似乎进入了那个领域。 Ramda will willingly tranform {moo: {goo: 'goo'}} into {moo: {goo: {boo: 'roo'}}} . Ramda 会心甘情愿地将{moo: {goo: 'goo'}}转换为{moo: {goo: {boo: 'roo'}}} But you have to tell it to do so more explicitly: assoc(['moo', 'goo'], {boo: 'roo'}) .但是你必须更明确地告诉它这样做: assoc(['moo', 'goo'], {boo: 'roo'})

So a request to change this might be a difficult sell... but it's a friendly crowd.因此,改变这一点的请求可能很难推销……但这是一群友好的人。 Feel free to bring it up there if you think it important.如果您认为这很重要,请随时提出。

I feel like I just have to import set function from lodash to prevent unexpected behavior.我觉得我只需要从 lodash 导入set函数来防止意外行为。

Remember, though, just how different the behaviors are.但请记住,行为是多么不同。 The biggest difference is that lodash is mutating its input, which Ramda won't do.最大的区别是 lodash 正在改变它的输入,而 Ramda 不会这样做。 They have different ideas about which values to enhance versus which ones to replace (as in the current example.) Of course their signatures are different.他们对要增强哪些值和替换哪些值有不同的想法(如当前示例中所示)。当然,他们的签名是不同的。 They have different behavior regarding array indices.它们在数组索引方面有不同的行为。 (I can't think of a way in lodash's set to add an object with string key '0', for instance. And Ramda certainly would not inlcude a constructed Rectangle when you call something like assocPath(['grid', 'width'], newVal, myObj) , whereas lodash would happily mutate the internal Rectangle object.) (例如,我想不出在 lodash 的set中添加一个字符串键为 '0' 的对象的方法。当你调用类似assocPath(['grid', 'width'], newVal, myObj) ,而 lodash 很乐意改变内部的 Rectangle 对象。)

In other words, they are different behaviors, designed for different purposes.换句话说,它们是不同的行为,为不同的目的而设计。 If lodash's behavior is what you want, by all means include it.如果 lodash 的行为是您想要的,请务必包含它。 But if you're using Ramda for most of your utility work, do note how different the philosophies are.但是,如果您在大部分实用程序工作中都使用 Ramda,请注意它们的理念有何不同。

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

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