A Gentle Introduction to Functional JavaScript: Part 2

Written by James Sinclair
on the 30th January 2016

This is part two of a three-part series introducing ‘functional’ programming in JavaScript. In the previous article, we saw how functions can be used to make certain code abstractions easier. In this article we apply these techniques to lists.

Working with Arrays and Lists

Recall that in the previous article, we talked about DRY code. We saw that functions are useful for bundling up sets of
actions that might be repeated. But what if we’re repeating the same function lots of times? For example:

That addColour function is called rather a lot. We are repeating ourselves—something we wish to avoid. One way to refactor it is to move the list of colours into an array, and call addColour in a for-loop:

This code is perfectly fine. It gets the job done, and it is less repetitive than the previous version. But it’s not particularly expressive. We have to give the computer very specific instructions about creating an index variable and incrementing it, and checking to see if it’s time to stop. What if we could wrap all that for-loop stuff into a function?

For-Each

Since JavaScript lets us pass a function as a parameter to another function, writing a forEach function is relatively straightforward:

This function takes another function, callback, as a parameter and calls it on every item in the array.

Now, with our example, we want to run the addColour function on each item in the array. Using our new forEach function we can express that intent in just one line:

forEach(addColour, colours);

Calling a function on every item in an array is such a useful tool that modern implementations of JavaScript include it as a built in method on arrays. So instead of using our own forEach function, we could use the built in one like so:

Map

Now, our forEach function is handy, but somewhat limited. If the callback function we pass in returns a value, forEach just ignores it. With a small adjustment, we can change our forEach function so that it gives us back whatever value the callback function returns. We would then have a new array with a corresponding value for each value in our original array.

Let’s look at an example. Say we have an array of IDs, and would like to get the corresponding DOM element for each of them. To find the solution in a ‘procedural’ way, we use a for-loop:

Again, we have to spell out to the computer how to create an index variable and increment it—details we shouldn’t really need to think about. Let’s factor out the for-loop like we did with forEach and put it into a function called map:

Reduce

Now, map is very handy, but we can make an even more powerful function if we take an entire array and return just one value. That may seem a little counter-intuitive at first—how can a function that returns one value instead of many be more powerful? To find out why, we have to first look at how this function works.

To illustrate, let’s consider two similar problems:

Given an array of numbers, calculate the sum; and

Given an array of words, join them together with a space between each word.1

Now, these might seem like silly, trivial examples—and they are. But, bear with me, once we see how this reduce function works, we’ll apply it in more interesting ways.

So, the ‘procedural’ way to solve these problems is, again, with for-loops:

These two solutions have a lot in common. They each use a for-loop to iterate over the array; they each have a working variable (total and sentence); and they both set their working value to an initial value.

Let’s refactor the inner part of each loop, and turn it into a function:

Now, this is hardly more concise but the pattern becomes clearer. Both inner functions take the working variable as their first parameter, and the current array element as the second. Now that we can see the pattern more clearly, we can move those untidy for-loops into a function:

Putting it all together

Now, as we mentioned before, these are trivial examples—the add and joinWord functions have fairly simple—and that’s kind of the point really. Smaller, simpler functions are easier to think about and easier to test. Even when we take two small, simple functions and combine them (like add and reduce, for example), the result is still easier to reason about than a single giant, complicated function. But, with that said, we can do more interesting things than add numbers together.

Let’s try doing something a little more complicated. We’ll start off with some inconveniently formatted data, and use our map and reduce functions to transform it into an HTML list. Here is our data:2

var ponies = [
[
['name', 'Fluttershy'],
['image', 'http://tinyurl.com/gpbnlf6'],
['description', 'Fluttershy is a female Pegasus pony and one of the main characters of My Little Pony Friendship is Magic.']
],
[
['name', 'Applejack'],
['image', 'http://tinyurl.com/gkur8a6'],
['description', 'Applejack is a female Earth pony and one of the main characters of My Little Pony Friendship is Magic.']
],
[
['name', 'Twilight Sparkle'],
['image', 'http://tinyurl.com/hj877vs'],
['description', 'Twilight Sparkle is the primary main character of My Little Pony Friendship is Magic.']
]
];

The data is not terribly tidy. It would be much cleaner if those inner arrays were nicely formatted objects. Now, previously, we used the reduce function to calculate simple values like strings and numbers, but nobody said that the value returned by reduce has to be simple. We can use it with objects, arrays, or even DOM elements. Let’s create a function that takes one of those inner arrays (like ['name', 'Fluttershy']) and adds that key/value pair to an object.

If we then use our map function we can convert the whole array into something more tidy:

var tidyPonies = map(ponyArrayToObject, ponies);

We now have an array of pony objects. With a little help from Thomas Fuchs' tweet-sized templating engine, we can use reduce again to convert this into an HTML snippet. The template function takes a template string and an object, and anywhere it finds mustache-wrapped words (like, {name} or {image}), it replaces them with the correponding value from the object. For example:

Once you understand the patterns that map and reduce are suited to, you may find yourself never needing to write an old-style for-loop again. In fact, it’s a useful challenge to see if you can completely avoid writing for-loops on your next project. Once you’ve used map and reduce a few times, you’ll start to notice even more patterns that can be abstracted. Some common ones include filtering, and plucking values from an array. Since these patterns come up quite often, people have put together functional programming libraries so that you can re-use code to address common patterns. Some of the more popular libraries include:

Now that you’ve seen how handy passing functions around as variables can be, especially when dealing with lists, you should have a whole suite of new techniques in your metaphorical tool-belt. And if that’s where you choose to leave it, that’s OK. You can quit reading here and nobody will think any less of you. You can go on to be a productive, successful programmer and never trouble your dreams with the complexities of partial application, currying or composition. These things are not for everyone.