- Use
forEach
to Work with an Array - Explain why
forEach
is the least-expressive collection-processing method
In the previous lesson, you learned that many of the collection-processing
functions are really slight variations on map
and reduce
.
But map
and reduce
are "child" collection-processing methods from the root
collection-processing method of them all, .forEach
. In this lesson, we'll talk
about forEach
and why it's a good idea to avoid it. Let's use it real quick.
By now, you're so comfortable with collection-processing methods, you'll find
.forEach
follows the pattern of the "Character of Collection-Processing
Methods."
oppressedWorkers = [
"Dopey",
"Sneezy",
"Happy",
"Angry",
"Doc",
"Lemonjello",
"Sleepy"
];
oppressedWorkers.forEach(function(oppressedWorker) {
console.log(`${oppressedWorker} wants to form a union!`);
}); //=> undefined
/* Output
Dopey wants to form a union!
Sneezy wants to form a union!
Happy wants to form a union!
Angry wants to form a union!
Doc wants to form a union!
Lemonjello wants to form a union!
Sleepy wants to form a union!
*/
We've saved talking about forEach
for last. Despite the fact that forEach
most simply expresses the "Character of collection-processing Methods," we're
showing it last because we want to use it least. Why is that?
We want to avoid forEach
because it is the least-expressive
collection-processing method. It communicates the least to other programmers
about what we're trying to do.
By now you recognize that map
means: "create a new Array
after transforming
each element." You recognize that reduce
means: "distill a value after
joining elements together." These methods are expressive, their very
definition tells other programmers what you intended to happen.
But what does forEach
mean? Programmers, including you, recognize that map
has
a specific use, reduce
has a specific use, max
has a specific use. But
forEach
is generic. Are we just printing things, or are we trying to distill to
a value, or are we trying to produce a transformed Array
?
When we use forEach
to do map
-things or reduce
-things we're not
documenting what our intention was with regard to the collection. This makes
for code that's harder to understand and debug. Here's some code that uses
forEach
instead of reduce
.
function sumArray(numberArray) {
let total = 0;
numberArray.forEach(function(i) {
total = total + i;
});
return total;
}
sumArray([1, 2, 3]); //=> 6
Sure, it works, but it doesn't communicate. We should always strive to have code that communicates first and works second.
The best time to use forEach
is when you need to enumerate a collection to
(1) cause some sort of "side-effect" or (2) are changing the elements
("mutating") as you go along.
The best example of "doing a side-effect" is using console.log()
. This
function doesn't return anything back. We don't care about the data that
returns from this action. We're using forEach
here strictly to do something
that, as side-effect is something that's handy for us i.e. printing content
to the screen.
This is pretty common in debugging:
empCollection.forEach(function(e){
console.log("DEBUG: WHAT ARE YOU?!?" + e)
})
The other time we want to use forEach
is when the element will be changed
by the process of forEach
-ing. Since the name forEach
is so
unexpressive, as casual readers of this code, anything that happens in here
is going to be a surprise, a side-effect.
As an example, consider:
function addFullNameToEmployees(empCollection){
empCollection.forEach(function(e){
e.fullName = `${e.firstName} ${e.familyName}`
})
}
addFullNameToEmployees([
{firstName: "Byron", familyName: "Karbitii"},
{firstName: "Luca", familyName: "Tuexedensis"}
])
There's nothing generated by the forEach
that we want to preserve (if that
were so, we'd want to use map
). The employee, e
, is updated as a
side-effect of running forEach
. The only clue that helps us guess what
forEach
is for here is that the programmer "wrapped" it inside of a
helpfully-named function name.
This concludes our discussion of forEach
. It's the most flexible
collection-processing method, but it's also the least expressive. When you
aren't sure which way to go, you might want to use it, but most of the time you
really want to use map
or reduce
.