HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptCritical

Loop (for each) over an array in JavaScript

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
arrayoverforeachloopjavascript

Problem

How can I loop through all the entries in an array using JavaScript?

Solution

TL;DR

-
Your best bets are usually

  • a for-of loop (ES2015+ only; spec | MDN) - simple and async-friendly


for (const element of theArray) {
// ...use
element...
}


  • forEach (ES5+ only; spec | MDN) (or its relatives some and such) - not async-friendly (but see details)


theArray.forEach(element => {
// ...use
element...
});


  • a simple old-fashioned for loop - async-friendly


for (let index = 0; index

  • (rarely) for-in with safeguards - async-friendly


for (const propertyName in theArray) {
if (/...is an array element property (see below).../) {
const element = theArray[propertyName];
// ...use element...
}
}


-
Some quick "don't"s:

  • Don't use for-in unless you use it with safeguards or are at least aware of why it might bite you.



  • Don't use map if you're not using its return value.


(There's sadly someone out there teaching
map [spec / MDN] as though it were forEach — but as I write on my blog, that's not what it's for. If you aren't using the array it creates, don't use map.)

  • Don't use forEach if the callback does asynchronous work and you want the forEach to wait until that work is done (because it won't).



But there's lots more to explore, read on...

JavaScript has powerful semantics for looping through arrays and array-like objects. I've split the answer into two parts: Options for genuine arrays, and options for things that are just array-like, such as the
arguments object, other iterable objects (ES2015+), DOM collections, and so on.

Okay, let's look at our options:
For Actual Arrays

You have five options (two supported basically forever, another added by ECMAScript 5 ["ES5"], and two more added in ECMAScript 2015 ("ES2015", aka "ES6"):

  • Use for-of (use an iterator implicitly) (ES2015+)



  • Use forEach and related (ES5+)



  • Use a simple for loop



  • Use for-in correctly



  • Use an iterator explicitly (ES2015+)



(You can see those old specs here: ES5, ES2015, but both have been superceded; the current editor's draft is always here.)

Details:
  1. Use for-of (use an iterator implicitly) (ES2015+)



ES2015 added iterators and iterables to JavaScript. Arrays are iterable (so are strings,
Maps, and Sets, as well as DOM collections and lists, as you'll see later). Iterable objects provide iterators for their values. The new for-of statement loops through the values returned by an iterator:



const a = ["a", "b", "c"];
for (const element of a) { // You can use let instead of const if you like
console.log(element);
}
// a
// b
// c



It doesn't get simpler than that! Under the covers, that gets an iterator from the array and loops through the values the iterator returns. The iterator provided by arrays provides the values of the array elements, in order beginning to end.

Notice how
element is scoped to each loop iteration; trying to use element after the end of the loop would fail because it doesn't exist outside the loop body.

In theory, a
for-of loop involves several function calls (one to get the iterator, then one to get each value from it). Even when that's true, it's nothing to worry about, function calls are very cheap in modern JavaScript engines (it bothered me for forEach [below] until I looked into it; details). But additionally, JavaScript engines optimize those calls away (in performance-critical code) when dealing with native iterators for things like arrays.

for-of is entirely async-friendly. If you need the work in a loop body to be done in series (not in parallel), an await in the loop body will wait for the promise to settle before continuing. Here's a silly example:



function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}

async function showSlowly(messages) {
for (const message of messages) {
await delay(400);
console.log(message);
}
}

showSlowly([
"So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// .catch omitted because we know it never rejects



Note how the words appear with a delay before each one.

It's a matter of coding style, but
for-of is the first thing I reach for when looping through anything iterable.
  1. Use forEach and related



In any even vaguely-modern environment (so, not IE8) where you have access to the
Array features added by ES5, you can use forEach (spec | MDN) if you're only dealing with synchronous code (or you don't need to wait for an asynchronous process to finish during the loop):



const a = ["a", "b", "c"];
a.forEach((element) => {
console.log(element);
});



forEach accepts a callback function and, optionally, a value to use as this` when calling that callback (not used above). The callback is called for each element in the array, in order, skipping non-existent elements in sparse arrays. Although I only used one parameter above, the callback is called with three arguments: The element for that

Code Snippets

Array.prototype.forEach.call(node.childNodes, (child) => {
    // Do something with `child`
});
// (This is all presumably in a module or some scoping function)
const forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);

// Then later...
forEach(node.childNodes, (child) => {
    // Do something with `child`
});
const divs = Array.from(document.querySelectorAll("div"));
// Typical use (with an arrow function):
const divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);

// Traditional function (since `Array.from` can be polyfilled):
var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
    return element.tagName;
});
const trueArray = [...iterableObject];

Context

Stack Overflow Q#9329446, score: 8594

Revisions (0)

No revisions yet.