I’ve been coding professionally for over 20 years. Here’s my take, for what it’s worth…
Working with collections (or lists) of things is very common. Needing to apply some logic to every item in a list is also extremely common. Generally, there are two ways to approach this:
- Recursion
- Iteration
Recursion means you have a function that calls itself. For example:
function countdownFrom(n) {
if(n <= 0) {
return
}
console.log(n)
countdownFrom(n-1)
}
Notice that the last line of the function above calls itself. This is recursion. There are two common problems with recursion:
- It tends to be hard to read and understand.
- Many programming languages are not optimized for this kind of code and will perform poorly when attempting to recurse. Interestingly, in 2015 the standard that JavaScript is based on introduced something called “tail call optimisation” which makes recursion fast, BUT most modern browsers STILL don’t support it.
Iteration is when you have a function that loops over a collection in some way. The for
loop is usually the first type of Iteration that most developers learn. It is generally taught in the form:
for (i = 0; i < collection.length; i++) {
// do something with collection[i]
}
Our countdown example from earlier could be written as follows:
for (i = 10; i > 0; i--) {
console.log(i)
}
Performing iteration with a for
loop has the following drawbacks:
- It requires the programmer to explicitly create and manage a loop counter. In the case of the above functions the
i
is our loop counter. Notice that we declare it, set its value, and increment it.
-
for
loops can be difficult to read and understand.
A for
loop is an example of what is called Imperative Programming.
Imperative programming is a style of programming where the code provides explicit instructions for how to achieve the desired result. Imperative code tends to be longer and more difficult to decipher. For this reason, experienced programmers tend to avoid the imperative style whenever possible.
The preferred style for most experienced programmers these days is Declarative Programming.
In declarative programming, we write code that describes what we want to do, instead of how we want to do it. JavaScript provides a number of ways to perform iteration using a declarative style.
In particular, the Array type in JavaScript exposes many Declarative style methods, the most popular are map
, reduce
, and filter
.
Typically, an experienced programmer will prefer one of these methods to a basic for
loop. Depending on what the program is trying to accomplish, a different method will be appropriate.
Let’s look at each one.
Map
Suppose we want to capitalize each word in an Array of words. With a for
loop we would write:
for (i = 0; i < words.length; i++) {
capitalizedWords.push(words[i].toUpperCase())
}
Using map
this becomes:
const capitalizedWords = words.map((word) => word.toUpperCase())
Reduce
Suppose we wanted to add all the numbers in an Array. With a for
loop we would write:
for (i = 0; i < numbers.length; i++) {
total += numbers[i]
}
Using reduce
this becomes:
const total = numbers.reduce((subTotal, number) => subTotal += number)
Filter
Suppose we wanted to remove all vowels from a word. for
:
for (i = 0; i < word.length; i++) {
if (!vowels.includes(word[i])) {
noVowels.push(word[i])
}
}
filter
:
const noVowels = word.split('')
.filter((letter) => !vowels.includes(letter))
Also of note, the declarative methods I described above are all what we call “higher order functions” and higher order functions are the gateway drug to a type of declarative programming known as functional programming which has seen a real rise in popularity over the last few years.
So, to re-iterate (see what I did there? ;)) the answer to your question is, most professionals prefer to avoid for
when a more declarative or functional option presents itself.