damtypo damtypo - 3 months ago 9
Javascript Question

Why is it useful to have an anonymous function stored as a variable, and pass it to higher order functions?

I am working on my understanding of functional programming and have a question.

In this example* an anonymous function is assigned to the variable isDog, then isDog is passed to filter. Then we can filter all the dogs in the animals array into a new array. (I know I can shorten this code, but that is not the point of the post :) )

var animals = [{name: "Spot", species: "dog"},
{name: "Rex", species: "dog"},
{name: "Whiskers", species: "cat"},
{name: "Floppy", species: "Rabbit"}]

var isDog = function(animal) {return animal.species === 'dog' }

var dogs = animals.filter(isDog)


I understand that functions can be passed as arguments and maybe that is made explicit by assigning functions to variables.

But now that the anonymous function is a variable and we don't write it with brackets i.e isDog(), intuitively it seems like this has made the code less readable. At first glance I would assume isDog is just a variable, and not a function.

Even if we can infer it is a function because it is attached to filter, it is still confusing and I assume there are other cases where it is not obvious. So now we have to look up what isDog is/does.

So what I am asking is why do this? It does look more elegant to have isDog without brackets, but is there any technical reason to use it this way?

Note, I understand the power of functions as arguments, my question is more about why assign them to a variable if it will make ambiguous code.

Thanks.

*Adapted from this helpful video. around 8min mark, https://www.youtube.com/watch?v=BMUiFMZr7vk

Answer

The brackets are only there when you're calling the function. If you pass the call with the brackets into the .filter() method, you'll actually be passing the result of the call, rather than a pointer to the call itself. The alternative is to pass in the entire function into the filter function, but readability tends to suffer. It also limits your ability to modify what's going into the function you're putting it in.

Imagine a case where you might want to do a sort instead of a filter, and you wanted to change the sort based on a boolean passed in.

Take this basic sort for example:

var numbers = [4, 2, 5, 1, 3];

numbers.sort(function(a, b) {
  return a - b;
});

What if you wanted to be able to choose which direction it was sorted based on another variable. You can define both sort functions, and then pass the correct one for the sort you want.

var numbers = [4, 2, 5, 1, 3];
var sortAscending = function(a, b) {
  return a - b;
}

var sortDescending = function(a, b) {
  return b - a;
}

function doSort(myArray, dir) {
    var sortMethod = (dir == "asc") ? sortAscending : sortDescending;
    myArray.sort(sortMethod );
}

doSort(numbers, "asc");

The above illustrates how passing the method call this way allows for more flexibility when you need it, and ensures the call is made only when it's executed inside sort.

Comments