Explain Codes LogoExplain Codes Logo

Loop through an array in JavaScript

javascript
array-iteration
asynchronous
best-practices
Anton ShumikhinbyAnton Shumikhin·Jul 22, 2024
TLDR
['apple', 'banana', 'cherry'].forEach((fruit, i) => console.log(`${i}: ${fruit}`));

Use forEach for a user-friendly and straightforward iteration. Here, fruit is the array element and i the index.

Pick your weapon: Array iteration methods

Different iteration methods are available for specific tasks. To transform elements and create a new array, use map:

const numbers = [1, 2, 3, 4]; const doubled = numbers.map(n => n * 2); // because everything's better in pairs!

Dispense with manual accumulation and use reduce to calculate accumulated values:

const sum = numbers.reduce((total, n) => total + n, 0); // "Reduce: Making addition lazy since 2015!"

For drawing out the seconds between acts, use filter to extract relevant elements:

const evens = numbers.filter(n => n % 2 === 0); // Odds out! Evens in!

For direct access to array values, the for...of loop is your mate:

for (const number of numbers) { console.log(number); }

Note that for...of is a tough cookie and handles arrays with missing elements, unlike forEach.

Sparse arrays and efficiency

Sparse arrays and hardcore optimization call for a traditional for loop with pre-cached length:

const myArray = ['first', , 'third']; for (let i = 0, len = myArray.length; i < len; i++) { if (myArray.hasOwnProperty(i)) { console.log(myArray[i]); // "I like my loops like I like my coffee, efficient and robust!" } }

Our friend, hasOwnProperty, makes sure you're logging only actual elements.

Plus one for indices

For keeping score value and index, Array#entries is your goal:

for (const [index, element] of numbers.entries()) { console.log(`Element at ${index}: ${element}`); }

Array Looping: Do's and Don'ts

The for...in should steer clear of arrays since it walks over all enumerable properties, not just numeric indices.

for (const index in myArray) { console.log(myArray[index]); // "The index is a lie!" }

Modifying Array.prototype is a big no-no. It can create a disruptive domino effect in iteration behavior.

ES6 compatibility

ES6 features may miss the mark in older environments. Always check your transpiled code or use friendly translators like Babel.

Generator functions

for...of loop and generator functions make a perfect combo for sequences, like Fibonacci numbers:

function* fibonacci() { let [a, b] = [0, 1]; while (true) { [a, b] = [b, a + b]; yield a; // "I'm just a loop, standing in front of a condition, asking it to yield." } } for (const num of fibonacci()) { if (num > 50) break; console.log(num); // console.log: "Who needs Fibonacci, when I'm here for your numbers?" }

Pitfall plaza and the map to cross it

Scopes and forEach

The forEach method does not establish its own scope meaning utilized variables are part of the outer scope. When in doubt, use functional expressions within .map() or .filter() for isolated scopes.

The asynchronous affair

Attempting to iterate asynchronously over arrays with forEach can lead to complications. In such situations, go with the for...of with await inside an async function:

async function processArray(array) { for (const item of array) { await process(item); // "Feel the rhythm, feel the rhyme, get on up, it's async time!" } }

Callbacks vs. for...of loop

While forEach saves you from lengthy lines of code, it's quite a diva and does not allow for breaks or continues. The for...of loop, however, is more accommodating.