Occasionally, I get stuck wondering what I should use to iterate over a list/collection of items in Javascript. There seem to be a hundred ways of achieving it. To tackle that and have a handy little reference, I'm writing this guide touching all the common ways of iterating that I use and the kind of data they are a good fit for.
for
1
2
3
4
5
6
7
8
const arr = ['apple', 'ball', 'cat'];
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// Output:
// apple
// ball
// cat
The regular for loop (with a loop variable that iterates from some number to some other number with user supplied increments) is the most common form of for loop. I try to use as little of this one as possible as there's usually a better suited loop available for the job. But if nothing else fits, know that the 'regular for' has your back.
for..in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const obj = {
firstName: 'John',
lastName: 'Doe'
}
for(const prop in obj) {
console.log(prop);
};
// Output:
// firstName
// lastName
const arr = [3, 2, 1];
for(const prop in obj) {
console.log(prop);
};
// Output:
// 0
// 1
// 2
for..in loop can be used to iterate over properties of an object. Supplying an array to for..in will give the index in the loop variable. In either case, doing a obj[prop] or arr[prop] should enable looping over the object's key values or array items.
for..of
1
2
3
4
5
6
7
8
const arr = [3, 2, 1];
for(const prop in obj) {
console.log(prop);
};
// Output:
// 3
// 2
// 1
for..of loop is useful for linearly looping over iterables like strings and arrays from the first to last item. I often mistake the for..in loop for this, but adding a new loop was how ES6 prevented breaking all the legacy code that depended on for..in to give array indices and not array items.
Array.prototype.forEach
1
2
3
4
5
6
7
8
const arr = ['World', 'Alice', 'Bob'];
arr.forEach(word => {
console.log('Hello', word);
});
// Output:
// Hello World
// Hello Alice
// Hello Bob
Array.prototype.forEach will accept a callback function (say (item [, index, array]) => {}
) and call it with each item in that array. An optional second argument will carry the current item's index. Optional third argument passes the reference of the original array if you wish to operate on it inside the callback.
Note that Array.prototype.forEach simply means that you can invoke this method directly on an array, like [3, 2, 1].forEach(...)
Array.prototype.map
1
2
3
4
5
6
7
const arr = [10, 20, 30];
const arr10x = arr.map(item => {
return item * 10;
})
console.log(arr10x);
// Output:
// [100, 200, 300]
Map maps over the items in the array, calls a callback with each item and returns a new array created from the values returned from callback functions.
Array.prototype.filter
1
2
3
4
5
6
7
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
const onlyEvens = arr.filter(item => {
return item % 2 == 0;
})
console.log(onlyEvens);
// Output:
// [2, 4, 6, 7]
Filter calls a callback function with each item in the array and returns a new array with only the elements for which the callback returns true. In general, the callback function implements the logic to determine if a given element should be present in the resultant filtered array (returns truthy if it should).
Array.prototype.reduce
1
2
3
4
5
6
7
const arr = [1, 2, 3, 4, 5, 6];
const sum = arr.reduce((accumulator, item) => {
return accumulator + item;
}, 0);
console.log(sum);
// Output:
// 21
It took my a long time to get used to Array.prototype.reduce, most likely because I don't use it often. But it shows up quite often when you're working on functional code, or functional programming languages like Haskell.
The Array.prototype.reduce method takes two arguments, a reducer function (of the signature (accumulator, curr) => return newAccumulator
) and an initial accumulator value. In the first iteration, the accumulator takes the initial value. In the next iterator, the return value of the previous iteration becomes the new accumulator value. After the last iteration, the accumulator value is returned from the Array.prototype.reduce method.
Object.keys() and Object.values()
1
2
3
4
5
6
7
8
9
10
const obj = {'a': 1, 'b': 2};
const keys = Object.keys(obj);
console.log(keys);
// Output:
// ['a', 'b']
const values = Object.keys(obj);
console.log(values);
// Output:
// [1, 2]
Object.keys() and Object.values() take in an object and return an array of all the keys and values of that object in an array respectively which can then be used with the looping methods discussed above.
Object.entries()
1
2
3
4
5
const obj = {'a': 1, 'b': 2};
const entries = Object.entries(obj);
console.log(entries);
// Output:
// [ ['a', 1], ['b', 2] ]
Object.entries takes in an object and returns a multidimensional array with each item a pair of key-value pair from the object.
while and do..while
1
2
3
4
5
6
7
8
9
const arr = [1, 2, 3, 4, 5];
const index = 0;
while(arr[index] < 4) {
console.log(arr[index]);
}
// Output:
// 1
// 2
// 3
while and do..while are the other classics apart from the good 'ol for loop. I don't use while and do..while loops for iteration. They're generally useful when you're repeating a task without knowing in advance the number of times you'll be repeating (for..in and for..of do that) or you'd want to only run the loop until a specific condition holds true (for can do that).
An interesting use case where while loops shine is when we need to iterate indefinitely (until the given condition is true), which isn't really iteration and hence I have put this section at the end, just as good to stuff.
In closing
That's it. I hope that simplifies iteration for you a bit. It certainly did for me. Did I miss any way of looping over iterables? Do let me know! I hope you learned something from this article. Thank you for reading!