其他答案假设您要将相关值设置为true。
但标题暗示您想要切换它们当前的布尔值。这是一个这样做的版本,如果我将输入的一个目标值切换为以 true 开头,这将更加明显。
const toggleFields = compose (evolve, compose (mergeAll, map (objOf (__, not))))
const currentObject = {
errors: false,
values: true,
warnings: false,
};
const template = ['values', 'warnings'];
console .log (toggleFields (template) (currentObject))
// => {
// errors: false, // ignored
// values: false, // toggled from true
// warnings: true // toggled from false
// }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script>const {compose, evolve, mergeAll, map, objOf, __, not} = R </script>
我们将['values', 'warnings'] 变成
evolve ({
values: not,
warnings: not
})
not 是 Ramda 的布尔切换函数,evolve 接受一个配置对象映射名称到转换器函数并返回一个函数,该函数接受一个对象并克隆它,通过适当的函数转换任何指定的属性。然后我们简单地用我们的源对象调用这个函数。
如果我们碰巧遇到字符枯竭,我们可以使用 Ramda curried,二进制合成函数 o,代替古老的 compose 本身:
const toggleFields = o (evolve, o (mergeAll, map (objOf (__, not))))
根据口味,我们也可以将objOf (__, not) 替换为flip (objOf) (not)。
推导
这个版本看起来很密集。我原来是这样写的:
const fn = (template) => (currentObject) => evolve (pipe (
map (objOf (__, not)),
mergeAll
) (template)) (currentObject)
但是在这里,如果我们稍微斜视一下,我们可以看到这个形式:
(x) => (y) => f (g (x)) (y)
x 代表 template,y 代表 currentObject,f 代表 evolve,g 代表其他所有内容。
而当我们有一个最终参数只应用在主体的末尾时,我们可以简单地消除它,所以和
(x) => f (g (x))
但这只是f 和g 的组合。所以我们可以这样写
compose (f, g)
然后用原来的代入我们得到
compose (
evolve,
pipe (map (objOf (__, not)), mergeAll)
)
我通常不喜欢在管道中混合compose 和pipe。我将compose 用于单行,pipe 用于更长的功能;对我来说,这开始看起来像一条线。所以我们交换map和mergeAll的顺序并切换到compose,得到这个:
compose (evolve, compose (mergeAll, map (objOf (__, not)))
香草
作为 Ramda 的创始人和主要作者,我实际上是经常建议人们尝试将它应用到他们不需要的地方的人。但是在这里我觉得这个版本比我想出的第一个香草JS版本要干净得多:
const toggle = (template) => (currentObject) =>
Object .fromEntries (
Object .entries (currentObject)
.map (([k, v]) => [k, template .includes (k) ? !v : v] )
)
这并不是坏事,我不会仅仅为了这个微小的改进而引入 Ramda。但如果我已经在使用 Ramda,那么 Ramda 版本似乎是一个改进。