如何使用ramda.js重构此代码?

时间:2016-06-30 15:12:50

标签: javascript ramda.js

我正在使用mithril.jsramda.js。我在秘银中有以下代码:

return m('ul.list-inline.text-center', [
     ctrl.items.map(item => R.allPass(item.policies)(item) ? m('li', m('a', {
          href: item.uri,
          config: m.route
      }, item.name)) : null)
]);

所以基本上我在ctrl.items上进行迭代,而item.policies只是一个返回true / false的简单函数数组。因此,如果一切都通过,则R.allPass(item.policies)(item)会为true提供{否} false,否则会决定是否呈现li标记。

所以我没有使用这个功能,而是认为创建这种功能更强大的方式会更好,因为我可以重用代码。因此,我认为我会filter使用R.allPass对项目而不是地图,而只是渲染过滤后的数组。

我开始在ramda中使用一个简单的过滤器摆弄,但我无法弄清楚如何实现结果:

var filterItems = R.filter(
    R.pipe(
        R.prop('policies'),
        R.allPass               
    )
);

这只返回完整的数组。它根本不排除任何项目。

1 个答案:

答案 0 :(得分:0)

嗯,从我对你的类型可以做出的,问题是你期望一个函数做双重任务。

假设items包含对象列表,例如:

const items = [
  {
    name: 'foo',
    val: 13,
    policies: [
      obj => obj.val > 10,
      obj => obj.val < 20,
      obj => obj.val % 2 == 1,
    ]
  },
  {
    name: 'bar',
    val: 14,
    policies: [
      obj => obj.val > 10,
      obj => obj.val < 20,
      obj => obj.val % 2 == 1,
    ]
  }
];

然后这个:

R.pipe(
    R.prop('policies'),
    R.allPass               
)

的类型如下:

const testPolicies = R.pipe(
    R.prop('policies'), // :: Item -> [(Item -> Boolean)]
    R.allPass           // :: [(Item -> Boolean)] -> Item -> Boolean
)                    // => :: Item -> Item -> Boolean

您需要将项目的两个副本传递给此函数,以使其返回布尔值。但是你把它当作只用一个就好了,好像它可以作为filter :: (Item -> Boolean) -> [Item] -> [Item]的输入。

您需要一种方法将(Item -> Item -> Boolean)转换为(Item -> Boolean)

Ramda没有任何内容可以帮助解决这个问题,尽管Ramda可能会考虑添加它,因为它偶尔会有用。但其中一个标准组合器 1 ,称为W就可以做到这一点:

const W = f => x => f(x)(x);

然后您可以像这样使用它:

R.filter(W(testPolicies), items); //=>
// {
//   name: 'foo',
//   val: 13,
//   policies: [
//     obj => obj.val > 10,
//     obj => obj.val < 20,
//     obj => obj.val % 2 == 1,
//   ]
// }

您可以在 Ramda REPL 上看到这一点。

1 Avaq's gist 中有一个很好的组合列表。