Javascript array iteration methods, when and which to use?
forEach
, map
, filter
, reduce
… so many to choose from! Which one should you pick, and why should you use them at all? And what’s wrong with my precious for
loop?!?
Well, nothing per se. However, I find that when I’m reading code that uses iteration methods properly (important) it helps to reduce cognitive load. Take the following examples:
While it’s true that one is less code, that isn’t the important part of the example. With example 1, I have to parse each line as I read it and put those pieces together to understand what the code is doing. Something like this (with my mental comments as JS comments):
This is a simple example. However, imagine more things going on in the for
loop; increasing its complexity is simple since it is already looping over all elements. Compare this to example 2:
That is the power of the iteration functions. Used properly (important again to note because they aren’t always), you have immediate understanding of what is being accomplished when you see one of these functions. With story time out of the way, let’s dig into what iterator functions there are, and when and how to use them!
Iterator Functions
Array.prototype.map() [MDN]
When to use: When you want to do something to every element in an array and return a new array with the new elements.
Side effects? The map
function should not produce side effects, i.e. don’t add something to another array or do something to the DOM in your map
function. Save that for a forEach
.
Using map
As you can see, there are a few ways to go about this, depending on whether arrow functions available. There are more things that your map function can take, e.g. the index of the array item. More details available at the MDN link provided at the beginning of this section.
Array.prototype.filter() [MDN]
When to use: Use filter
anytime you want to create a new array from an old one, but only want to include elements that meet a certain criteria.
Side effects? No! Your filter
function should be very simple.
Using filter
Filter is probably the simplest of the iterator functions. It takes a function that takes an item, and returns a boolean which determines whether or not that item should be added to the new array.
Array.prototype.forEach() [MDN]
When to use: You can use forEach
anytime you just want to do something with every item in an array, but you don’t care about the resulting elements. An example might be “for each item in this array, log it to the console”. You could use a map
(or even a filter
) for that, but the proper way would be to use a forEach
. This function is the closest direct comparison to a for
loop, since you can do basically whatever you want. If you are using your forEach
to add elements to an array, you should strongly consider whether forEach
is the right method to use.
Side effects? Sure! That’s more or less the point of this guy. In terms of functional programming, forEach
is probably what some would refer to as the “red headed stepchild” of the bunch (though I wouldn’t, because red-heads are alright in my books).
Using forEach
Array.prototype.reduce() [MDN]
Last but not least, we have reduce
. This is the big daddy of all the iterator functions. You can create all the other iterator functions using reduce. Reduce is the most powerful and also the least well understood of the iterator functions in my opinion.
When to use: You should probably almost never use reduce
… for array transformations at least. Reduce does what its name suggests: reduce
an array into some other form, be it an array, a string, a boolean, whatever you want. If you need super specific control or you need to map and combine entities, a reduce
is a good choice.
Side effects? No!
Using reduce
Reduce is probably the most fun one out of the bunch. It has the most unique signature as well. From MDN:
arr.reduce(callback[, initialValue])
initialValue
is optional but is what makes reduce
great. If you don’t pass it in, the first item in the array is used for the initialValue
. The other thing that makes reduce
tricky is the callback function takes the accumulated reduced value and the current value, and it’s up to you to take the current value and reduce
it into the accumulated one. Some examples of its use:
Start using these functions!
I think these functions are great, for a few reasons:
- They reduce cognitive load to people reading your code down the line (as long as they aren’t nested too deep)
- They are less code to write (not as important as #1)
- They can make your code look more expressive, as they can be chained together nicely, something I didn’t even get into today!
I find it fun to reconsider for loops and look at how they could be converted to these iterator functions. Something that helped me understand them better and got me started on functional programming at all was this article by Mary Rose Cook. Check it out.
What about break?
This is one of the few times it makes sense to use a plain ol’ for loop (a POFL) — if you have a huge array and need to break out of it early. An example would be looking for a single item that matches a criteria and finishing early. You could do that with a forEach
, but then you can’t break out. The alternative to doing this in a for loop would be to use one of the newer array methods, like array.some() or array.every() to accomplish one of those tasks!