我正在构建一个React应用程序。我正在使用Ramda来帮助我进行函数式编程。
如果你想看到完整的代码,我也请求StackExchange Code Review的帮助。
但是,对于Stack Overflow,只有一部分是相关的。
如何使用Ramda根据对象的其他值更改对象的特定值?我使用mapObjIndexed
,它在过程中映射所有键。
上下文:我在对象上表示与几个键的联系人,这些键都是字符串。该对象始终有一个名为contactDetails
的键。我想计算contactDetails
的值,该值取决于对象的tel
,bday
和email
键的值。
如果联系人在函数之前看起来像这样:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
之后它应该是这样的:
{
firstName: 'John',
lastName: 'Doe',
contactDetails: '[email protected] 555-55-5555',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
我为此编写的函数如下所示:
R.mapObjIndexed((val, key, obj) =>
key === 'contactDetails'
? R.trim(
R.replace(
/undefined/g,
'',
`${R.prop('bday')(obj)} ${R.prop('tel')(obj)} ${R.prop('email')(
obj
)}`
)
)
: val
),
正如你所看到的,这是一种非常不洁净和黑客的方式滥用map
。有没有更好的方法根据对象的其他值更改Ramda中的对象值?
除非这是学习Ramda的练习,否则我会建议一种比Ramda可能提出的更简单的技术是直接的对象解构方法:
const transform = ({tel, bday, email, ...rest}) => ({
...rest, tel, bday, email,
contactDetails: [bday, email, tel].join(' ').trim()
})
const obj = {firstName: 'John', lastName: 'Doe', tel: '555-55-5555', bday: '', email: '[email protected]'}
console.log(transform(obj))
这个版本不依赖于已经存在的密钥contactDetails
,尽管如果它存在就不会受到伤害。
如果您真的担心单词之间可能存在双重空格(例如,如果提供了bday
和tel
,但email
为空),您可以将其修改为:
const combine = (ss) => ss.reduce((a, s) => a + (s.length ? ' ' : '') + s, '').trim()
const transform = ({tel, bday, email, ...rest}) => ({
...rest, tel, bday, email,
contactDetails: combine([bday, email, tel])
})
我是Ramda的创始人之一,也是一个大粉丝,但它只是一个工具包。有很多地方可以帮助您的代码更易于阅读和编写;一定要用它然后。但是当它没有这样做时,即使在使用Ramda的代码库中,也要跳过它并使用其他技术。
作为Ori答案的替代方法,我们可以使用R.assoc('contactDetails')
更新属性,使用R.juxt
和R.propOr('')
构建所需属性值的列表以默认任何缺少的属性,在与R.join
连接之前拒绝任何空字符串。
// takes a list of property names, returning a function that accepts an object
// and produces a list of the values of the provided properties, defaulting to
// an empty string if null or undefined.
const defProps =
R.compose(R.juxt, R.map(R.propOr('')))
const fn =
// When `g` is a function, `R.chain(f, g)(x)` is equivalent to `f(g(x), x)`
R.chain(
R.assoc('contactDetails'),
R.pipe(
defProps(['bday', 'tel', 'email']),
R.reject(R.equals('')),
R.join(' ')))
console.log(fn({
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
您可以使用R.converge合并原始对象,以及生成contactDetails
属性的R.pipe的结果。管道通过R.props获取值数组,过滤掉有价值的值(未定义,空字符串,空值等等),使用空格连接项目,并使用R.objOf将对象包装起来。
const { converge, merge, identity, pipe, props, filter, join, trim, objOf } = R
const fn = converge(merge, [identity, pipe(
props(['bday', 'tel', 'email']),
filter(Boolean),
join(' '),
objOf('contactDetails')
)])
const obj = {
firstName: 'John',
lastName: 'Doe',
contactDetails: '',
tel: '555-55-5555',
bday: '',
email: '[email protected]'
}
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>