DEV Community

Duncan McArdle
Duncan McArdle

Posted on • Originally published at duncan-mcardle.Medium

4 1

Battle of the JavaScript for loops (for, for…in, for…of, forEach, etc.)

Iterating over objects and arrays is something every developer has to do. Whether you’re a beginner or a seasoned veteran, eventually you’re going to have to find something in a larger data set. But when iterating (looping) through something, you might find yourself a little lost with all of the options available to you. So here’s a quick breakdown of the main ones.

Note: This isn’t a beginner's introduction to how for loops work, but rather a comparison of the for loop options available.

for (the classic)

for is by far the most common loop. It isn’t specific to arrays or objects (or to any data structure in fact), and can be combined with almost anything to create powerful and fast loops, so long as you configure them properly. Here’s a classic for loop in action:

const someArray = [1, 2, 3];
for (let i = 0; i < someArray.length; i++) {
console.log(someArray[i]);
// Outputs:
// 1
// 2
// 3
}

for loops can be used in conjunction with break, continue or return to create some seriously versatile functionality.

forEach

forEach allows you to return an entire entry from an array. It’s simple and straightforward, but doesn’t come with the additional break, continue and return functionality found with a classic for loop. It does however, look incredibly clean.

const someArray = [1, 2, 3];
someArray.forEach((entry) => {
console.log(entry);
// Outputs:
// 1
// 2
// 3
});

Think of a forEach loop as being like a cleaner, array-specific for loop.

for...in

The for...in loop allows you to loop through the enumerable properties of an object, including those set by the parent prototype (if one is present).

// Declare a parent object
const parentObject = {
prop1: 'Parent prop 1',
prop2: 'Parent prop 2',
};
// Declare a child object, which prototypes the parent
const childObject = Object.create(parentObject);
// Add an additional option to the child object
childObject.prop3 = 'Child prop';
// for ... in loop
for (key in childObject) {
console.log(childObject[key]);
// Outputs (not in this order):
// 'Parent prop 1'
// 'Parent prop 2'
// 'Child prop'
}

Now unfortunately, that’s probably not what you want. You could put a check in on each iteration to see if the property belongs to the object or its prototype (hasOwnProperty would be perfect here), but that really damages readability. In addition, for...in loops only return strings, so if you’re looping through an array (which does, despite the mention of properties above, work), you probably don’t want to use one of these.

for...of

for…of iterates over any enumerable object, won’t convert the values it finds, and does so whilst supporting the functionality of break, continue and return.

const someArray = [1, 2, 3];
for (val of someArray) {
console.log(val);
// Outputs:
// 1
// 2
// 3
}

Think of for...of as being like a cleaner version of the for loop, specifically for iterable objects, without losing any of the for loop’s functionality.

The Object class

One consistent downside of the above for loops is that their compatibility with objects vary. That all changes however, with the use of the Object class.

By using Object, we can convert our objects to arrays (I promise that’ll make sense shortly), and then loop through those arrays with all of the above loops.

Now, you’ll commonly see forEach used in conjunction with this method, but the problem with that is that you lose the ability to break, continue or return during the loop. For that reason, I’d recommend considering a classic for loop in conjunction with this method, but here’s an example of both for completeness (note that this example uses Object.keys(), which is covered below):

const someObject = {
prop1: 'Value 1',
prop2: 'Value 2',
};
// Loop through the object's properties using Object.keys (with a forEach - can't use break, continue or return)
Object.keys(someObject).forEach((key) => {
console.log(someObject[key]);
// Outputs:
// Value 1
// Value 2
});
// Loop through the object's properties using Object.keys (with a for - can use break, continue and return)
for (let i = 0, keys = Object.keys(someObject); i < keys.length; i++) {
console.log(someObject[keys[i]]);
// Outputs:
// Value 1
// Value 2
}

Object.keys()

This handy function returns an array of keys found in the specified object. Even more handily, it only includes keys belonging to the immediate object, and not its prototype, so that means no more seeing the parent props like we do with for...in.

// Declare a parent object
const parentObject = {
prop1: 'Parent prop 1',
prop2: 'Parent prop 2',
};
// Declare a child object, which prototypes the parent
const childObject = Object.create(parentObject);
// Add an additional option to the child object
childObject.prop3 = 'Child prop';
// Object.keys loop (forEach)
Object.keys(childObject).forEach((key) => {
console.log(childObject[key]); // Only outputs 'Child prop'
});

Object.entries()

This one returns each and every entry in its entirety, including both the property and value. This can be more helpful if you want to retain the key that you’re seeing the value of (which you often do).

const someObject = {
prop1: 'Prop 1 value',
prop2: 'Prop 2 value',
};
Object.entries(someObject).forEach((entry) => {
console.log(entry, dunno);
// Outputs:
// [ 'prop1', 'Prop 1 value' ]
// [ 'prop2', 'Prop 2 value' ]
});

Object.values()

As the name suggests, this method returns only the values found in an object. No index, no key, just values.

const someObject = {
prop1: 'Prop 1 value',
prop2: 'Prop 2 value',
};
Object.values(someObject).forEach((value) => {
console.log(value);
// Outputs:
// Prop 1 value
// Prop 2 value
});

Wrapping things up

You might have reached this point and be hoping for me to say “So make sure kids, that you always use the best loop, the <insert loop here>”.

But c’mon, that’s rarely how programming works.

In reality, the right approach for you depends entirely on the context. Some of the above methods are faster than others, some are more useful, others are more readable. It’s up to you to find the right combination of the above, but hopefully this has helped you on your way to making that decision.

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more