Higher Order Functions (Composing Software) - by Eric Elliott - JavaScript Scene - Medium
Higher Order Functions (Composing Software) - by Eric Elliott - JavaScript Scene - Medium
Become a member
Note: This is part of the “Composing Software” series (now a book!) on learning functional
programming and compositional software techniques in JavaScriptES6+ from the ground up. Stay
tuned. There’s a lot more of this to come!
Buy the Book | Index | < Previous | Next >
Earlier we saw examples of .map() and .filter() . Both of them take a function as an
argument. They're both higher order functions.
Let’s look at an example of a first-order function which filters all the 4-letter words from a list
of words:
Now what if we want to select all the words that begin with ‘s’? We could create another
function:
You may already be recognizing a lot of repeated code. There’s a pattern forming here that
could be abstracted into a more generalized solution. These two functions have a whole lot in
common. They both iterate over a list and filter it on a given condition.
Both the iteration and the filtering seem like they’re begging to be abstracted so they can be
shared and reused to build all sorts of similar functions. After all, selecting things from lists
of things is a very common task.
Luckily for us, JavaScript has first class functions. What does that mean? Just like numbers,
strings, or objects, functions can be:
Passed as arguments
Returned from functions
Basically, we can use functions just like any other bits of data in our programs, and that
makes abstraction a lot easier. For instance, we can create a function that abstracts the
process of iterating over a list and accumulating a return value by passing in a function that
handles the bits that are different. We’ll call that function the reducer:
This reduce() implementation takes a reducer function, an initial value for the accumulator,
and an array of data to iterate over. For each item in the array, the reducer is called, passing it
the accumulator and the current array element. The return value is assigned to the
accumulator. When it's finished applying the reducer to all of the values in the list, the
accumulated value is returned.
In the usage example, we call reduce and pass it the function, (acc, curr) => acc + curr ,
which takes the accumulator and the current value in the list and returns a new accumulated
value. Next we pass an initial value, 0, and finally, the data to iterate over.
With the iteration and value accumulation abstracted, now we can implement a more
generalized filter() function:
const filter = (
fn, arr
) => reduce((acc, curr) => fn(curr) ?
acc.concat([curr]) :
acc, [], arr
);
In the filter() function, everything is shared except the fn() function that gets passed in as
an argument. That fn() argument is called a predicate. A predicate is a function that returns
a boolean value.
We call fn() with the current value, and if the fn(curr) test returns true , we concat the
curr value to the accumulator array. Otherwise, we just return the current accumulator
value.
Now we can implement censor() with filter() to filter out 4-letter words:
Wow! With all the common stuff abstracted out, censor() is a tiny function.
And so is startsWithS() :
If you’re paying attention, you probably know that JavaScript has already done this
abstraction work for us. We have the Array.prototype methods, .reduce() and .filter() and
.map() and a few more for good measure.
Higher order functions are also commonly used to abstract how to operate on different data
types. For instance, .filter() doesn't have to operate on arrays of strings. It could just as
easily filter numbers, because you can pass in a function that knows how to deal with a
different data type. Remember the highpass() example?
In other words, you can use higher order functions to make a function polymorphic. As you
can see, higher order functions can be a whole lot more reusable and versatile than their first
order cousins. Generally speaking, you’ll use
Openhigher
in app order functions in combination with very
Eric Elliott is a distributed systems expert and author of the books, “Composing Software” and
“Programming JavaScript Applications”. As co-founder of DevAnywhere.io, he teaches developers the
skills they need to work remotely and embrace work/life balance. He builds and advises development
teams for crypto projects, and has contributed to software experiences for Adobe Systems,Zumba
Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank
Ocean, Metallica, and many more.
He enjoys a remote lifestyle with the most beautiful woman in the world.
Follow
1K 21
1.1K 25
1.1K 12
Eric Elliott in JavaScript Scene
262 3
69
98 1
Lists
Staff Picks
310 stories · 77 saves
629 35
Patrick Kalkman in ITNEXT
737 5
John Raines
501 9