The Right Tool for the Job: An In-Depth Look at JavaScript Array Loops
25/09/2025
When you first start learning to code, you quickly get introduced to the classic for
and while
loops. But as you dig deeper into JavaScript, you discover there are many newer, "fancier" ways to iterate over an array.
If you're like me, you've probably wondered: "Why are there so many options, and when should I use which one?"
I learned this the hard way when I tried to jump back and forth in an array using for…of
with Array.entries()
as I was trying to impress at an interview, just to find out that it wasn’t working as I expected.
I fumbled. I tried to manipulate the index inside the for...of
loop (index = index + value), but the iterator just kept moving forward, ignoring my assignment. I panicked because I realized I overcomplicated. And in the end, I had to start from scratch with another solution.
After the interview I still had this question in the back of my mind: "Why didn't it work?" So I went back to the docs to find my answer.
In this article, we'll explore the nuances of each iteration method, clarifying their ideal use cases and highlighting the key distinction between direct index control and sequential traversal.
Statements vs. Expressions: A Core JavaScript Concept
The behavior of different iteration methods is tied to a fundamental concept of JavaScript: the difference between a statement and an expression.
- A statement is a command that performs an action, but it doesn't return a value.
- An expression produces a value that can be assigned, returned, or passed around.
*This distinction is crucial because it determines where you can use a piece of code. Contexts like the curly braces {}
in React's JSX expect an expression to render, which is a key reason why .map()
is the preferred method for creating lists.
Quick Reference
for
loop → Statement (executes a block of code, returns nothing)while
loop → Statement (executes a block of code, returns nothing)for...of
loop → Statement (executes a block of code, returns nothing)forEach()
→ Expression (Executes a callback for side effects; it returns undefined and is not for transforming data).map()
→ Expression (evaluates to a new array of values)
Looping Methods: Strengths and Limitations
For a concrete example, we will use a common data structure: an array of objects and we will breakdown each looping method with a common goal - finding the "Keyboard" and stopping.
const products = [
{ id: 1, name: "Laptop", price: 1200 },
{ id: 2, name: "Mouse", price: 25 },
{ id: 3, name: "Keyboard", price: 75 },
{ id: 4, name: "Monitor", price: 300 },
{ id: 5, name: "USB Hub", price: 15 },
];
1. The Classic for
Loop: The Power of Manual Control
The classic for
loop is a statement that provides complete control over the iteration process. You can access the index, modify the counter (i
), and jump, skip, or reverse direction at any point. This makes it ideal for complex or conditional traversal logic , giving you the possibility to break
at any time.
for (let i = 0; i < products.length; i++) {
console.log(`Processing item ${i}: ${products[i].name}`);
if (products[i].name === "Keyboard") {
console.log("Keyboard found! Breaking the loop.");
break;
}
}
// Output:
// Processing item 0: Laptop
// Processing item 1: Mouse
// Processing item 2: Keyboard
// Keyboard found! Breaking the loop.
2. The while
Loop: Another Form of Manual Control
Similar to the for
loop, the while
loop is a statement that offers full control over the index. The primary difference is in syntax and structure - it's often used when the number of iterations isn't known beforehand. Like the for
loop, it is perfect for scenarios requiring precise control over the flow,including the ability to break
.
let i = 0;
while (i < products.length) {
console.log(`Processing item ${i}: ${products[i].name}`);
if (products[i].name === "Keyboard") {
console.log("Keyboard found! Breaking the loop.");
break;
}
i++;
}
// Output:
// Processing item 0: Laptop
// Processing item 1: Mouse
// Processing item 2: Keyboard
// Keyboard found! Breaking the loop.
3. forEach()
: The Simple, Forward-Only Loop
The forEach()
method call is an expression that is a clean, readable way to execute a function for each element in an array. However, you can't use break
to exit the loop early, nor can you skip elements or jump to a specific index. It is designed for straightforward, complete traversal.
products.forEach((product, i) => {
console.log(`Processing item ${i}: ${product.name}`);
if (product.name === "Keyboard") {
console.log("Keyboard found! Cannot break the loop.");
// No `break` or `return` will stop the forEach() loop.
}
});
// Output:
// Processing item 0: Laptop
// Processing item 1: Mouse
// Processing item 2: Keyboard
// Keyboard found! Cannot break the loop.
// Processing item 3: Monitor
// Processing item 4: USB Hub
4. for...of
: The Modern Iterator
The for...of
loop is the modern standard for iterating directly over the values of an iterable object like an array. It is highly readable and safe, but fundamentally different from a for
loop. It’s forward-only: you can’t skip, jump, or reverse direction, because it relies on the iterator protocol, which only provides the next value in sequence. However, a key advantage over forEach()
is that it does support break
and continue
.
for (const product of products) {
console.log(`Processing: ${product.name}`);
if (product.name === "Keyboard") {
console.log("Keyboard found! Breaking the loop.");
break;
}
}
// Output:
// Processing: Laptop
// Processing: Mouse
// Processing: Keyboard
// Keyboard found! Breaking the loop.
5. .entries()
, .keys()
, .values()
: Unpacking the Iterator
These methods (.entries(), .keys(), .values()
) return an iterator object. When used with a for...of
loop, they allow you to access different aspects of the array. The .entries()
method, for example, returns a pair of [index, value], which can be destructured for easy access. However, the core behavior remains: the iteration is strictly forward.
for (const [i, product] of products.entries()) {
console.log(`Processing item ${i}: ${product.name}`);
if (product.name === "Keyboard") {
console.log("Keyboard found! Breaking the loop.");
break;
}
}
// Output:
// Processing item 0: Laptop
// Processing item 1: Mouse
// Processing item 2: Keyboard
// Keyboard found! Breaking the loop.
6. The .map()
Method: Transforming Arrays
The .map()
method is an expression that's designed to transform an array and return a new one of the exact same length. Its purpose is to process every single element in the original array, so you cannot use break
to exit the loop early. This makes it perfect for creating a new array without modifying the original.
//Use .map() to create a new array with just the product names
const productNames = products.map(product => product.name);
console.log(productNames);
// Output:
// ["Laptop", "Mouse", "Keyboard","Monitor","USB Hub"]
The Fundamental Difference: Manual Index vs. Sequential Traversal
The key distinction between these methods is how they control iteration:
-
Classic
for
andwhile
loops give you direct control over the index. You can skip, jump, reverse, orbreak
at any point. This is essential for complex traversal logic, such as non-linear or conditional paths through the array. -
Methods like
forEach()
and.map()
are designed for sequential, forward-only traversal. They abstract away the index, providing a clean API for processing each element in order. You cannotbreak
, skip, or jump — just process every element. -
For...of
is a hybrid: it uses the iterator protocol, which means it moves forward one element at a time. UnlikeforEach()
and.map()
, it supportsbreak
andcontinue
. However, you still cannot manipulate the index or move backward.
When to Use What
- Use the classic
for
orwhile
loops when your code requires manual control over the iteration index, such as jumping, skipping, or reversing direction. - Use
forEach()
when you need to execute a function for every element in a linear, non-interruptible fashion. - Use
for...of
for simple, readable iteration over array values, and when you may need tobreak
orcontinue
. - Use
.map()
when you need to transform an array into a new array, which is particularly common in UI development with frameworks like React.
Final Thought: Every Mistake is a Step Forward
What you perceive as failure is just feedback. Every bug, every mistake, is a chance to learn something new. That interview didn’t go as planned, but it taught me something every developer should remember:
- Don’t optimize early - Start small, then refine.
- Understand the tool - Each loop has a purpose. Pick the one that matches your task.
Next time you hit a wall, ask yourself:
- What am I really trying to do?
- What’s the simplest way to do it?
- Do I understand the trade-offs?
By understanding these distinctions, you can write code that is not only functional but also clear, efficient, and well-suited to its task. Sometimes, the answer is a humble for
loop. And that’s okay.