The many different type of for loops in javascript

This discussion has a more recent version.

There are a ton of different for loops that are available in javascript. With our current browser support and polyfills all of them are available to us in our compiled javascript.

We'll use the following values for all of our iterations.

const nodeList = document.querySelectorAll(".someClass");
const arr = [1, 2, 3];
const obj = {
    key: "val",
    key2: "val2",
};

Simple Loop

This loop only works with arrays. Classic for loop.

for (let i = 0; i < arr.length; i++) {
    const value = arr[i];
    // Iterate;
}

For In Loop

This loop only works with Objects. It does not provide the key. Don't forget the hasOwnProperty check!

// For in
// Only works for objects
for (const val in obj) {
    // You HAVE to use this or your loop could be broken by some client code adding things to Object.prototype.
    if (obj.hasOwnProperty(val)) {
        // Iterate
    }
}

forEach() with an array

// Array.prototype.forEach()
arr.forEach((value, index) => {
    // Iterate
});

forEach() with an "ArrayLike" on old browser without a polyfill.

// Array.prototype.forEach() with an "ArrayLike" with no polyfill.
Array.prototype.forEach.apply(nodeList, (node, index) => {
    // Iterate
});

forEach() with an "ArrayLike" on an old browser that has Array.prototype.from

// Array.prototype.forEach() with an "ArrayLike" with Array.from (or polyfill)
Array.from(nodeList).forEach((node, index) => {
    // Iterate
});

forEach() with an "ArrayLike" on a modern browser with polyfills

// NodeList.prototype.forEach() (or polyfill)
nodeList.forEach((node, index) => {
    // Iterate
});

forEach() with Object

Object.keys(obj).forEach((key, index) => {
    const value = obj[key];
});

Object.values(obj).forEach((value, index) => {
});

Object.entries(obj).forEach(([key, value], index) => {
});

For Of Loop with an Array

// for of loop with an array. No access to the index.
for (const value of arr) {
    // Iterate
}

For Of Loop with an Object.

// for of loop with an object keys, values
for (const key of Object.keys(obj)) {
}
for (const value of Object.values(obj)) {
}
for (const [key, value] of Object.entries(obj)) {
}

Which one do I use?

I would definitely avoid for in and Array.from and Array.prototype.forEach.apply() because we have better options.

  • Manually counting for loop - If you need total control of the iteration and may need to increment or decrement the counter yourself. A while loop might be more appropriate for these scenarios.
  • forEach() - In a more functional style, and if you prefer Promises directory over async/await.
  • for of - If you are using async await or prefer a more imperative style.

Consider the following function and it's usage. If you want to use async/await you pretty much have to use the for of loop instead.

function getDllPLuginsForAddonDirectories(directories: string[], entryKey: string, options: ICliOptions) {
    return directories
        .filter(addonUsesCoreBuildProcess)
        .map(getManifestPathsForDirectory)
        .reduce((accumulator: string[], manifests: string[]) => accumulator.concat(manifests), [])
        .filter(filterManifestPathsByEntryKey(entryKey))
        .map(manifest => {
            return new webpack.DllReferencePlugin({
                context: options.vanillaDirectory,
                manifest: require(manifest),
            });
        });
}

forEach version

function doSomeAsyncAction() {
    return getDllPLuginsForAddonDirectories(["/asd", "/asd"], "app", {});
        .forEach(plugin => {
            // Do something with it
            doAnAsyncThing(plugin).then(() => {
                // Followup
            });
        }).catch(e => {
            // Error handling.
        })
}

for of version

async function doSomeAsyncAction() {
    const plugins = getDllPLuginsForAddonDirectories(["/asd", "/asd"], "app", {});

    try {
        for (const plugin of plugins) {
            await doSomeAsyncAction(plugin);
            // Followup
        }
    } catch (e) {
        // Error handling
    }
}