Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In .filter() how do I make a callback function call another function?

I'm trying to get the hang of callback functions but I've ran into something that I don't fully understand.

This block of code works great when it's used in the example below.

zombieCreatures = creatures.filter(filterCreatures);

Unfortunately this block of code doesn't work when it's used in the same example.

zombieCreatures = creatures.filter(function(v) {
    filterCreatures(v);
});

To me they look like identical instructions but obviously I am incorrect. What is the difference? Is it possible to make a callback function call another function inside of .filter()?

'use strict';

var creatures = [], zombieCreatures = [];

var filterCreatures;

creatures = [
  {species: 'Zombie', hitPoints: 90},
  {species: 'Orc', hitPoints: 40},
  {species: 'Skeleton', hitPoints: 15},
  {species: 'Zombie', hitPoints: 85}
];
	
filterCreatures = function(v) {
  return v.species === 'Zombie';
}
	
zombieCreatures = creatures.filter(function(v) {
  filterCreatures(v);
});

console.log(zombieCreatures);
like image 363
DR01D Avatar asked Oct 31 '25 05:10

DR01D


2 Answers

Yes, you can certainly call any other functions inside a filter callback.

The only thing you're missing is that the callback needs to return a value. Your callback doesn't have a return statement. It calls the filterCreatures() function, but then it discards the value returned by that function and by default returns undefined.

Compare with the original version of your code:

creatures.filter(filterCreatures);

In this code, filter() calls the filterCreatures function directly and then uses its return value to decide whether to include the element. You don't see this explicitly in the code, but filter() is looking for that return value.

Here's an exercise to help clarify this. Take your broken code and move the inline filter callback out to a named function. We'll call it filterCreaturesWrapper. So instead of this:

filterCreatures = function(v) {
  return v.species === 'Zombie';
}

zombieCreatures = creatures.filter(function(v) {
  filterCreatures(v);
});

we have this:

filterCreatures = function(v) {
  return v.species === 'Zombie';
}

filterCreaturesWrapper = function(v) {
  filterCreatures(v);
}

zombieCreatures = creatures.filter(filterCreaturesWrapper);

If you study that, you'll see it's exactly the same code as before, we just moved it around a little. filterCreaturesWrapper is the same function that was inline inside the .filter() call. And now the problem should jump out at us: filterCreatures has a return statement and filterCreaturesWrapper doesn't.

Going back to the original broken code, it's as if we had written:

zombieCreatures = creatures.filter(function(v) {
  filterCreatures(v);
  return undefined;  // .filter treats this as 'false'
});

So just add a return in your callback and it works:

'use strict';

var creatures = [], zombieCreatures = [];

var filterCreatures;

creatures = [
  {species: 'Zombie', hitPoints: 90},
  {species: 'Orc', hitPoints: 40},
  {species: 'Skeleton', hitPoints: 15},
  {species: 'Zombie', hitPoints: 85}
];
	
filterCreatures = function(v) {
  return v.species === 'Zombie';
}
	
zombieCreatures = creatures.filter(function(v) {
  return filterCreatures(v);  // <-- added "return"
});

console.log(zombieCreatures);

Not every language works like this. Ruby, for example, returns the last expression in a method (function) whether you explicitly say return or not. So if you were writing Ruby code (assuming all the other bits were converted to Ruby too), your code would have worked!

like image 85
Michael Geary Avatar answered Nov 02 '25 20:11

Michael Geary


filter will call the function it was given for every item in the array. It will check the return value of that function for every item and if the return value is truthy, it will add that item in a new array.

On other words, it returns an array of all items for which the callback returns a truthy value.

In the first example, you are passing the filterCreatures function directly, which returns true when the creature is a zombie.

In the second example, you're passing another function and calling filterCreatures internally, but not returning anything meaning the callback passed to filter returns undefined for every item, which is falsy and nothing gets filtered.

For it to work, you must return the result of calling filterCreatures:

zombieCreatures = creatures.filter(function(v) {
    return filterCreatures(v);
});

That being said, adding the additional function around filterCreatures doesn't have much use when filterCreatures itself does everything you need.

like image 33
nem035 Avatar answered Nov 02 '25 19:11

nem035