for...in Loops versus for...of Loops
Greetings, friends! It's showdown time! The battle between for...in
loops and for...of
loops in JavaScript. What is the difference between them and when do we use each of them? The for...in
loop is used to iterate over keys in an object, but only keys that are considered enumerable
as we learned in the previous tutorial. The for...of
loop is used to iterate over objects that are considered iterable such as Arrays, Strings, Maps, and Sets.
Loosely speaking, it comes down to these two things:
for...in
-> enumerability -> objectsfor...of
-> iterability -> arrays, strings, maps, sets
A useful mnemonic that helps me is that "in" sounds similar to "en" in the word, "enumerable." That means the other loop, for...of
, relates to iterables.
When to use the for...in Loop
We should use the for...in
loop when we want to quickly iterate over keys in an object, but we want control over what properties are considered enumerable
.
const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
console.log(key);
}
/* OUTPUT:
a
b
c
*/
However, there are other ways to iterate through the keys of an object. We could have used the Object.keys method with the Array.forEach method.
const obj = { a: 1, b: 2, c: 3 };
Object.keys(obj).forEach(key => console.log(key));
/* OUTPUT:
a
b
c
*/
Using a for...in
loop looks much nicer than the above approach, don't you think? Another reason you may want to use a for...in
loop is when you want to configure the enumerable
property descriptor as we learned in the previous tutorial.
const mathConstants = {
E: Math.E,
LN10: Math.LN10,
LN2: Math.LN2,
PI: Math.PI,
TAU: Math.PI * 2,
metaData: 'This object contains math constants',
};
Object.defineProperty(mathConstants, 'metaData', {
enumerable: false
});
for (const key in mathConstants) {
console.log(key);
}
/* OUTPUT:
E
LN10
LN2
PI
TAU
*/
This approach may give you the flexibility you're looking for when developing code. JavaScript's flexibility can create some interesting patterns that may be more difficult to implement in other languages!
In the example above, we have created an object that contains a bunch of math constants, but the key named metaData
is hidden when we use a for...in
loop. It's important to note that the Object.keys
method is also designed to return only the enumerable
keys on an object, so the following code is practically equivalent to the above code snippet with only a difference in performance.
const mathConstants = {
E: Math.E,
LN10: Math.LN10,
LN2: Math.LN2,
PI: Math.PI,
TAU: Math.PI * 2,
metaData: 'This object contains math constants',
};
Object.defineProperty(mathConstants, 'metaData', {
enumerable: false
});
Object.keys(mathConstants).forEach(key => console.log(key));
/* OUTPUT:
E
LN10
LN2
PI
TAU
*/
Why We Avoid for...in Loops with Arrays
You may have read that you shouldn't use a for...in
loops with arrays because they can iterate over properties attached to arrays that have non-integer names.
Let's look at a basic example of using for...in
loops with arrays.
const food = ['pizza', 'donut', 'potato'];
for (const key in food) {
console.log(key);
}
/* OUTPUT:
0
1
2
*/
We get back 0, 1, 2
because arrays are simply a special type of object in JavaScript. The keys of an array will be the indices, and the values of the array will be the elements in the array.
const food = ['pizza', 'donut', 'potato'];
for (const key in food) {
console.log(food[key]);
}
/* OUTPUT
pizza
donut
potato
*/
Since arrays are just fancy objects in JavaScript, this also means we can be a bit crazy and attach new properties to arrays. Let's add a non-integer property to the array called metaData
. When we use a for...in
loop, we can still see the value of metaData
.
const food = ['pizza', 'donut', 'potato'];
food.metaData = 'list of the best food';
for (const key in food) {
console.log(food[key]);
}
/* OUTPUT
pizza
donut
potato
list of the best food
*/
Compare this with a for...of
loop that only iterates through the integer properties of an array. That is, only the indices of the array.
const food = ['pizza', 'donut', 'potato'];
food.metaData = 'list of the best food';
for (const value of food) {
console.log(value);
}
/* OUTPUT
pizza
donut
potato
*/
Looks like the metaData
property was skipped! Interesting! This tells us that using a for...in
loop with an array is probably not the best idea. If you're using a library of code developed by someone, then they could have attached non-integer properties to their arrays. This is why it's generally preferable to use arrays with for...of
and objects with for...in
.
Using for...of Loops with Objects
If we try using a for...of
loop with an object, it will likely fail. This is because objects aren't considered iterable or array-like by default.
There are ways to make an object iterable as mentioned in my tutorial on iterators, iterables, and generators, but it seems like a lot of overhead when we can easily iterate through keys or values of an object using Object.keys, Object.values, or Object.entries.
Conclusion
The main difference between for...in
loops and for...of
loops is that the former iterates over enumerable properties of an object, and the latter iterates through iterables such as arrays. Each loop statement has its own advantages and disadvantages. Use the one that's right for you! You may even find that sticking with normal for loops works better for you. JavaScript gives us lots of choices, but it's important to know the difference between each type of loop structure. Happy coding! :)