如何在 JavaScript 中以 lodash 的 wrap 样式构建过滤器链?

How can I build, in JavaScript a filter chain, in the style of lodash's wrap?

明确地说,给定一个对象数组,可能具有同质键:

const data = [
  { name: "tomato", isHealthy: true, "calories": 300 },
  { name: "french fries", isHealthy: false, "calories": 1000 },
  { name: "lettuce", isHealthy: true, "calories": 100 },
  { name: "nacho cheese", isHealthy: false, "calories": 1200 },
  { name: "boring chicken", isHealthy: true, "calories": 500 },
];

还有一些过滤器说:

const isHealthy = function(items) {
  return items.filter(i => i.isHealthy);
};

const caloriesAbove = function(items, calories) {
  return items.filter(i => i.calories > calories);
};

我希望能够像这样调用过滤器链:

wrapper(data).isHealthy().caloriesAbove(500).value.map(...)

有点难看出lodash是如何做到这一点的。此外,有没有办法做到这一点 w/o 必须显式解包才能获得价值?这不是必需的,因为我认为这可能必须使用不受欢迎的技巧。

lodash 是这样做的:

 function wrapper(items) {
    return {
        value: items,
        isHealthy() { 
          return wrapper(items.filter(it => it.isHealthy));
        },
        caloriesAbove(calories) {
          return wrapper(items.filter(it => it.calories > calories));
        },
    };
 }

Further, is there a way to do this w/o having to explicitly unwrap in order to get the value?

从 ES6 开始,您可以扩展数组:

  class Items extends Array {
    isHealthy() {
      return this.filter(it => it.isHealthy);
    }
  }

要将现有数组转换为项目,只需执行 Items.from(array)new Items(...array) 然后您可以:

  items
    .filter(it => it.calories > 2) // native methods can be used, they return Item instances, not Arrays
    .isHealthy() // our custom methods also work
    .map(it => it.name)[0] //its a regular array with indices.

我阅读了答案,我喜欢@Jonas 的处理方式。不知道你可以像那样简单地扩展数组。定义。得到了我的赞成票!

话虽如此,我想知道当您可以简单地创建一个过滤器函数来处理多个值并将其传递给数组的过滤器时,这种方法有多大用处:

const data = [
  { name: "tomato", isHealthy: true, "calories": 300 },
  { name: "french fries", isHealthy: false, "calories": 1000 },
  { name: "lettuce", isHealthy: true, "calories": 100 },
  { name: "nacho cheese", isHealthy: false, "calories": 1200 },
  { name: "boring chicken", isHealthy: true, "calories": 500 },
];

const myFilterFn = ({isHealthy, calories}) => isHealthy && calories > 200

data.filter(myFilterFn).map(x => console.log(x))

我在更通用的视图中看到了它的价值,但对于过滤来说,它似乎有点矫枉过正。

只是我的 2 美分。