Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript array filter() with bind()

I'm using the filter() array helper going through some objects in an array. My idea is to create a dynamic filtering function to go through the objects in the array using bind(), but the arguments in bind are being used in a different way that I expected. Here's the code:

var products = [
  {name:"lettuce", type:"vegetable"},
  {name:"apple", type:"fruit"},
  {name:"carrot", type:"vegetable"},
  {name:"orange", type:"fruit"}
];

// this is the function used in filter()
function filterProducts(cat, product){
  return product.type === cat;
}

// new array
var vegetables = products.filter(filterProducts.bind(products, "vegetable"));

I'm assuming that the filter helper is passing each object in the array after the arguments in the bind method, so first is the products which accounts for this in the callback, then is the type I want to check on each object and finally the object itself.

The question is: Would you recommend doing it like this? I mean, could this be considered a good practice or would it be better to create a function to filter each type instead of doing it like this?

like image 725
Rodrigo Avatar asked Jul 29 '16 17:07

Rodrigo


2 Answers

Consider using a factory function instead:

var products = [
  {name:"lettuce", type:"vegetable"},
  {name:"apple", type:"fruit"},
  {name:"carrot", type:"vegetable"},
  {name:"orange", type:"fruit"}
];

function filterProducts(category) {
  // this is the function used in filter()
  return function filter(product) {
    return product.type === category;
  };
}

// new array
var vegetables = products.filter(filterProducts("vegetable"));

console.log(vegetables);

I would recommend this pattern over using bind, as it's a little easier to follow, at least in my opinion.

Clarification

If you intend to use filterProducts solely as a factory for Array#filter(), then congratulations, you've finished reading this answer. If you're complaining that the following is "icky":

// product to be validated
var product = {name:"lettuce", type:"vegetable"};

// validate that product is a vegetable
if (filterProduct('vegetable')(product)) {
  // code
}

Then keep reading.


Factory functions are good for defining a class of functions that differ by one or two key variables. In this case the key variable is category. If you want a one-off function that looks nice in a single line of code, you're gonna be hard-pressed to find one unless you're a lodash aficionado or something... but for this scenario, consider this instead of the above "icky" block of code:

// product to be validated
var product = {name:"lettuce", type:"vegetable"};
// vegetable validator
var isVegetable = filterProduct('vegetable');

// validate that product is a vegetable
if (isVegetable(product)) {
  // code
}

Sure, bind can be good in some situations, and I'm definitely not suggesting you avoid it at all costs, but you should first ask yourself whether it's really necessary or clean to use it before resorting to it.

like image 189
Patrick Roberts Avatar answered Oct 16 '22 09:10

Patrick Roberts


This is really a matter of opinion. Some people use bind more than others. With es6 arrow notation, writing the function in the callback will prob be preferred over binding.

Only note I would make is that for clarity, when using bind,

var sayName = function(name){
  console.log(name)
}
var sayTony = sayName.bind(null,'Tony')

It's best practice to put null in as the first argument if it's not being used inside the function.

If you really value readability you can be more explicit and declare another function.

function filterProducts(cat, product){
  return product.type === cat;
}
var filterVegtables = filterProducts.bind(null, 'vegtable');

then you can do

var vegetables = products.filter(filterVegtables);
like image 30
lonewarrior556 Avatar answered Oct 16 '22 10:10

lonewarrior556