Difference Between JavaScript Loops: For, ForEach(), For…of, and For…in
A cheat sheet for JavaScript developers
In this article, I am explaining the differences between the four for
loops in JavaScript.
tl;dr
The best use for these loops is as follows:
- For arrays, use
for...of
(orforEach
). - For objects, use
for...in
. - If you work with arrays and need access to indexes, use
for
orforEach
.
for...in
loop
This loop was introduced in ES6 as a tool to use with enumerables to iterate over the properties of the object:
Now, you can iterate over an array with this tool, but that doesn’t mean you should. It works because in JS, arrays inherit from the Object
. Because of that, the bracket notation ([]
) will have a similar effect if you call this looping tool on an array as it will if you call it on an object. However, there are two caveats: Arrays impact speed and situations when you're dealing with a NodeList
or just inconsistent data in an array.
As for speed, the situation is clear: When iterating over arrays, for...in
is much slower than the for...of
loop that is specific to arrays, strings, and NodeLists
.
To understand the issues with inconsistent data, you need to remember that Array
is an Object
, and as such, you can assign to it properties (which should not happen, but may):
let students = ["SpongeBob", "Patrick"]
students.name = "Mr. Krabs"students
// ["SpongeBob", "Patrick", name: "Mr. Krabs"]
This is an example of inconsistent data and we would wish that our loop would just disregard it. However, for...in
was created to iterate over properties, and so it will do just that:
This is especially important when it comes to, for instance, NodeList
s that look like an array but in fact also hold a bunch of other elements (e.g., methods) and it’s best if they were skipped altogether.
for...of
loop
Also introduced in ES6, for...of
is specific to iterables: arrays, strings, NodeList
s, sets, and maps. It comes with a great set of features:
It checks whether an element is iterable (using GetIterator operation) and throws an appropriate TypeError
if it's not:
Compare it with for...in
(which you should not use on arrays):
It supports all kinds of control flow in the loop body, like continue
, break
, yield
and await
.
It’s faster than forEach
.
forEach
There’s this syntactic sugar, forEach
, which takes up to three arguments:
arr.forEach(callback(currentElement, index, array) {
// do something <- this is a callback
});
These are:
currentElement
— the element that's being acted on (this one is the only mandatory one)index
— the current index of the elementarray
— the array that's being iterated over
A benefit to forEach
is that you do have access to the index, which for...of
does not give you. (Well, there is a lengthy way of obtaining one, but it's overkill.) Also, this is a finite loop by definition, and so it will end at some point, even if you don't factor in a break
statement for an edge-case situation.
There’s another, more obscure benefit: The temporary variable (currentElement
in the example above) is locally scoped, whereas that is not so in the for...of
loop. See here:
In the above example, we can see that forEach
has not overwritten the value of the num
variable declared outside of its scope, whereas that was not the case with the for...of
loop. However, if you can't name your variables in a more descriptive way, there still is a fix for that: Use let
inside of the for...of
array.
for
loop
This loop is just the oldest and most widely supported for
loop in JS. You can always rely on it. It also allows you to be more intentional about which is the starting/ending element and which direction the iteration should go.
However, the dev experience is not perfect because its syntax is not straightforward. Feel free to use for...in
(when dealing with objects) or for...of
(when dealing with arrays, strings, sets, NodeList
s, and maps) instead where appropriate.