Using Map and Reduce in Functional JavaScript

Share this article

With all the talk about workflows that support the amazing new features in ECMAScript 6, it’s easy to forget that ECMAScript 5 brought us some great tools to support functional programming in JavaScript which we can use today. Among these are the native map() and reduce() methods on the base JavaScript Array object.

If you’re not using map() and reduce() today, it’s time you started. Most contemporary JavaScript platforms support ECMAScript 5 natively. Mapping and reducing can make your code much cleaner and more easy to read and maintain, and put you on a path toward more elegant functional development.

Performance: A Caveat

Of course, reading and maintaining your code has to be balanced against performance when the situation calls for it. Currently browsers do perform more efficiently using more cumbersome traditional techniques, such as for loops.

My approach is usually to write code for readability and maintainability first, and then optimize for performance if I notice issues in real world situations. Premature optimization is the devil.

It’s also worth considering that using methods such as map() and reduce() may take better advantage of improvements in the JavaScript engine as browsers optimize for them in the future. Unless I’m up against the wall on a performance issue, I prefer to code optimistically, and keep performance tweaks that make my code less attractive in my back pocket in case I need them.

Using Map

Mapping is a fundamental functional programming technique for operating on all of the elements in an array and producing another array of the same length with transformed contents.

To make that a little bit more concrete, let’s come up with a simple use case. For example, imagine that you have an array of words, and you need to transform that into an array that contains the length of each word. (I know, that’s not the sort of complex rocket science you often need to do for your sophisticated application, but understanding how it works in a simple case like this will help you apply it in cases where it can add real value to your code).

You probably already know how to do what I just described using a for loop on the array. It might look something like this:

var animals = ["cat","dog","fish"];
var lengths = [];
var item;
var count;
var loops = animals.length;
for (count = 0; count < loops; count++){
  item = animals[count];
  lengths.push(item.length);
}
console.log(lengths); //[3, 3, 4]

All we did was define a few variables: an array called animals that contained our words, an empty array called lengths that will contain the output of our operation, and a variable called item to temporarily store each of the items that we were going to be manipulating within each loop of the array. We set up a for loop with a temporary internal count variable and a loops variable to optimize our for loop. Then we iterated through each of the items up to the length of the animals array. For each one we calculated the length, and pushed that onto the lengths array.

Note: Arguably we could have done this a little more concisely without the item variable by pushing the length of animals[count] directly to the lengths array without an intervening assignment. That would have saved us a little bit of code, but it would also make things less readable, even for this very simple example. Similarly, to make this more performant but a little less straightforward, we could have used the known length of the animals array to initialize our lengths array as a new Array(animals.length), and then inserted items by index instead of using push. It all depends on how you’re going to use the code in the real world.

There’s nothing technically wrong with this approach. It should work in any standard JavaScript engine, and it will get the job done. But once you know how to use map(), doing it this way just looks clunky.

Let me show you how we might approach this using map():

var animals = ["cat","dog","fish"];
var lengths = animals.map(function(animal) {
  return animal.length;
});
console.log(lengths); //[3, 3, 4]

In this case, once again we started with a variable for our animals array of animal types. However, the only other variable we declared was lengths, and we assigned its value directly to the result of mapping an anonymous in-line function onto each element of the animals array. That anonymous function performed an operation on each animal, returning the length. As a result, lengths became an array of the same length as the original animals array, containing the length of each word.

A few things to notice about this approach. First of all, it’s much shorter than the original. Second, we had to declare far fewer variables. Fewer variables means less noise in the global namespace, and less opportunities for collisions if other parts of the same code use variables with the same names. Additionally, none of our variables ever had to change their values from beginning to end. As you get deeper into functional programming, you’re going to appreciate the graceful power of using constants and immutable variables, and it’s never too early to start.

Another advantage of this approach is that we have the opportunity to improve its versatility by splitting out a named function, producing cleaner code in the process. Anonymous in-line functions can look messy, and make it harder to reuse code. We could have defined a named getLength() function and used it in context this way:

var animals = ["cat","dog","fish"];
function getLength(word) {
  return word.length;
}
console.log(animals.map(getLength)); //[3, 3, 4]

See how clean that looks? Just making mapping part of your toolkit can take your code to a whole new functional level.

What’s a Functor?

As a point of interest, by adding mapping to the array object, ECMAScript 5 turned the basic array type into a full functor, making functional programming even more accessible to all of us.

According to classical functional programming definitions, a functor meets three criteria:

  1. It holds a set of values
  2. It implements a map function to operate on each element
  3. Its map function returns a functor of the same size

That’s one to toss around at your next JavaScript Meetup.

If you’d like to learn more about functors, check out this great video by Mattias Petter Johansson.

Using Reduce

The reduce() method is also new in ECMAScript 5, and it’s similar to map(), except that instead of producing another functor, reduce() produces a single result that may be of any type. For example, imagine that you wanted to get the sum of the lengths of all of the words in our animals array as a number. You might start by doing something like this:

var animals = ["cat","dog","fish"];
var total = 0;
var item;
for (var count = 0, loops = animals.length; count < loops; count++){
  item = animals[count];
  total += item.length;
}
console.log(total); //10

After we define our initial array, we create a variable total for the running total, set initially to zero. We also create a variable item to hold each iteration of the animals array as it goes through the for loop, and a variable count for the loop counter, as well as a loops variable to optimize our iterations. Then we run a for loop to iterate through all of the words in the animals array, assigning each one to the item variable. Finally we add the length of each item to our total.

Again, there’s nothing technically wrong with this approach. We start with an array, and we end up with a result. But with the reduce() method we can make this much more straightforward:

var animals = ["cat","dog","fish"];
var total = animals.reduce(function(sum, word) {
  return sum + word.length;
}, 0);
console.log(total);

What’s happening here is that we’re defining a new variable, total, and assigning it the result of reducing the animals array using two parameters: an anonymous in-line function, and an initial running total value of zero. Reducing goes through each item in an array, performs a function on that item, and adds it to a running total that is passed to the next iteration. Here our in-line function takes two parameters: the running sum, and the word that is currently being processed from the array. The function adds the current value of total to the length of the current word.

Notice that we’re setting the second argument of reduce() to zero, and this establishes that total will contain a number. Without that second argument the reduce method will still work, but the result won’t necessarily be what you would expect. (Give it a try and see if you can derive the logic JavaScript uses when the running total is left off.)

That may look a little bit more complicated than it needs to because of the integrated definition of an in-line function while invoking the reduce() method. Let’s do that again, but let’s define a named function first, instead of using an anonymous in-line function:

var animals = ["cat","dog","fish"];
var addLength = function(sum, word) {
  return sum + word.length;
};
var total = animals.reduce(addLength, 0);
console.log(total);

This is a little longer, but longer isn’t always a bad thing. Seeing it this way should make it a little bit clearer what’s happening with the reduce method.

The reduce() method takes two parameters: a function to apply for each element in the array, and an initial value to use for the running total. In this case we’re passing the name of a new function called addLength and the initial value of zero for the running total. We’ve created the addLength() function so that it also takes two parameters: a running sum, and a string to process.

Conclusion

Getting used to using map() and reduce() on a regular basis will give you alternatives to make your code cleaner, more versatile, and more maintainable, and pave your way toward using more functional JavaScript techniques.

The map() and reduce() methods are only two of the new methods that were added to ECMAScript 5. In all likelihood, the improvements in code quality and developer satisfaction you’ll see from using them today will far outweigh any temporary impact on performance. Develop with functional techniques, and measure the impact in the real world before deciding whether map() and reduce() are right for your application.

This article was peer reviewed by Panayiotis Velisarakos, Tim Severien and Dan Prince. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Frequently Asked Questions (FAQs) about Map-Reduce in Functional JavaScript

What is the difference between Map and Reduce in JavaScript?

In JavaScript, both Map and Reduce are higher-order functions that operate on arrays. The Map function is used to create a new array by applying a function to each element of the original array. It does not modify the original array but returns a new one. On the other hand, the Reduce function is used to reduce the array to a single value. It applies a function to each element of the array (from left to right) so as to reduce it to a single output value.

How does the Map function work in JavaScript?

The Map function in JavaScript works by creating a new array from an existing one. It does this by applying a specified function to each element in the original array. The function is called once for each element in the array, in order. The result is a new array with the results of the function calls.

How does the Reduce function work in JavaScript?

The Reduce function in JavaScript works by applying a function to each element in an array, in order, so as to reduce the array to a single output value. The output value is the accumulated result of the function calls. The function takes two arguments: the accumulator and the current value. The accumulator accumulates the return values of the function calls.

Can I use Map and Reduce together in JavaScript?

Yes, you can use Map and Reduce together in JavaScript. In fact, they are often used together in functional programming. You can use the Map function to transform each element in an array, and then use the Reduce function to combine the transformed elements into a single output value.

What is the difference between Map and ForEach in JavaScript?

Both Map and ForEach are higher-order functions in JavaScript that operate on arrays. The main difference between them is that Map creates a new array by applying a function to each element of the original array, while ForEach applies a function to each element of the array for its side effects. ForEach does not return a new array.

How can I use the Map function to transform an array in JavaScript?

You can use the Map function in JavaScript to transform an array by applying a function to each element of the array. The function is called once for each element in the array, in order. The result is a new array with the results of the function calls.

How can I use the Reduce function to combine the elements of an array in JavaScript?

You can use the Reduce function in JavaScript to combine the elements of an array into a single output value. The function is applied to each element in the array, in order, and the output value is the accumulated result of the function calls.

What are some common use cases for the Map function in JavaScript?

The Map function in JavaScript is commonly used to transform an array by applying a function to each element of the array. Some common use cases include converting strings to numbers, changing the case of strings, and extracting properties from objects.

What are some common use cases for the Reduce function in JavaScript?

The Reduce function in JavaScript is commonly used to combine the elements of an array into a single output value. Some common use cases include summing numbers, finding the maximum or minimum value, and concatenating strings.

How can I debug a Map or Reduce function in JavaScript?

You can debug a Map or Reduce function in JavaScript by using console.log statements within the function to display the values of variables and expressions. You can also use the debugger statement to pause execution and inspect the values of variables and expressions in the developer tools of your web browser.

M. David GreenM. David Green
View Author

I've worked as a Web Engineer, Writer, Communications Manager, and Marketing Director at companies such as Apple, Salon.com, StumbleUpon, and Moovweb. My research into the Social Science of Telecommunications at UC Berkeley, and while earning MBA in Organizational Behavior, showed me that the human instinct to network is vital enough to thrive in any medium that allows one person to connect to another.

array methodsfor loopsfunctional programmingfunctional-jsfunctorsmapreduce
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week