Search code examples
javascriptlodashecmascript-2016

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


To be clear, given an Array of Objects, likely with homogenous keys:

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 },
];

and a few filters say:

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

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

I'd like to be able to call the filter chain like:

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

It is a bit difficult to see how lodash accomplishes this. Further, is there a way to do this w/o having to explicitly unwrap in order to get the value? This is not a requirement as I think this might have to use undesirable hacks.


Solution

  • This is how lodash does it:

     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?

    Since ES6 you can extend arrays:

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

    To turn an existing array into Items, just do Items.from(array) or new Items(...array) then you can:

      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.