JAVASCRIPT • CONTROL FLOW

for...of & Index Loops — Iterate arrays with for...of and index-based loops

Master two essential patterns for visiting every element in a JavaScript array efficiently and clearly.

Historical Context & Motivation

From the earliest days of programming, developers have needed a way to repeat actions across collections of data. Imagine you have a list of 1,000 student names and you need to print each one. Writing 1,000 separate console.log() statements would be absurd. Loops solve this problem by letting you write one block of code that automatically repeats for every item in a collection.

JavaScript has evolved significantly over its three decades. Early versions offered only the classic for loop with an index counter, which gave programmers precise control but also invited common mistakes. As the language matured, new loop styles were introduced to make iteration safer and more readable.

1995
JavaScript Created
Brendan Eich creates JavaScript in 10 days at Netscape. The original language includes the classic for loop borrowed from C and Java, using an index variable to count through arrays.
1999
ECMAScript 3 & for...in
ES3 standardizes for...in, designed to iterate over object properties. Developers sometimes misuse it on arrays, leading to subtle bugs because it iterates over keys (including inherited ones), not values.
2009
ES5 Adds forEach
The Array.prototype.forEach() method arrives, providing a callback-based approach. It is cleaner than index loops for simple tasks but cannot be exited early with break.
2015
ES6 Introduces for...of
ECMAScript 2015 (ES6) brings the for...of loop, designed specifically for iterating over iterable objects like arrays, strings, Maps, and Sets. It gives direct access to values with full support for break and continue.

Today's JavaScript developer has multiple tools for iterating arrays. The central question this lesson addresses is: when should you use a for...of loop versus a traditional index-based for loop, and how do you write each one correctly? By the end of this lesson, you will be able to choose the right loop for any situation.

Core Principles & Definitions

Before diving into syntax, it helps to understand the foundational ideas behind array iteration. An array is an ordered collection of values, where each value sits at a numbered position called an index. The first element lives at index 0, the second at index 1, and so on. Iteration means visiting each element in order and performing some action on it.

1

Index-Based for Loop

Uses a counter variable (usually i) that starts at 0 and increments until it reaches array.length. You access elements via array[i]. Best when you need the index or want to skip/reverse elements.
2

for...of Loop

Iterates directly over the values of an iterable. No index counter needed. The loop variable holds the current element on each pass. Best for clean, readable code when you only need values.
3

Iteration vs. Indexing

Iteration is the act of going through each element one by one. Indexing is accessing a specific element by its position number. An index-based loop combines both; for...of focuses on iteration alone.
4

Loop Control: break & continue

Both loop styles support break (exit the loop immediately) and continue (skip the current iteration and move to the next). This gives you full control over the looping process.
✦ KEY TAKEAWAY
Think of an array like a row of lockers in a school hallway. An index-based loop is like walking down the hall reading each locker number before opening it — you always know which locker you are at. A for...of loop is like having someone hand you the contents of each locker in order — you get what you need without worrying about the numbers at all.

Visual Explanation

The diagram below shows how each loop style processes the same array. On the left, the index-based for loop tracks a counter variable i that advances from 0 to 3. On the right, the for...of loop directly receives each value without managing an index. Both visit every element, but their internal mechanics differ.

Left: the index-based for loop tracks a counter variable i and accesses elements by position. Right: the for...of loop hands you each value directly, hiding the index mechanics.

Notice how the left panel requires you to initialize i, test i < arr.length, and increment i++ — three separate pieces you must get right. The right panel eliminates all of that. JavaScript's iteration protocol handles advancement and termination behind the scenes, so you just write your logic inside the loop body.

How Each Loop Works Under the Hood

The Index-Based for Loop

The classic for loop has three parts inside its parentheses, separated by semicolons: initialization, condition, and update. Here is the general pattern:

INDEX LOOP SYNTAX
for (let i = 0; i < array.length; i++) { /* use array[i] */ }
let i = 0 — initialization: create counter at 0. i < array.length — condition: keep going while true. i++ — update: add 1 to the counter after each pass.

The engine runs the initialization once, then repeats a cycle: check the condition → if true, execute the body → run the update → repeat. The moment the condition evaluates to false, the loop exits. Because arrays are zero-indexed, you typically use i < array.length (strict less-than) rather than <=. Using <= would try to access one element past the end of the array, resulting in undefined — a classic off-by-one error.

The for...of Loop

FOR...OF SYNTAX
for (const element of array) { /* use element */ }
const element — a new variable created on each iteration holding the current value. of array — tells JavaScript which iterable to traverse.

Behind the scenes, for...of uses the array's built-in iterator protocol. JavaScript calls a hidden method (Symbol.iterator) to get an iterator object, then repeatedly calls .next() on it. Each call returns { value, done }. When done is true, the loop stops. You do not need to manage any of this yourself — JavaScript handles it automatically.

💡 Getting the Index with for...of
If you want both the index and the value, combine for...of with array.entries(): for (const [i, val] of arr.entries()) { ... }. The .entries() method returns pairs of [index, value], and destructuring unpacks each pair into two variables.

Syntax Patterns & Variations

Both loop styles have useful variations beyond the basic pattern. Understanding these will help you handle real-world situations like iterating backward, skipping elements, or exiting early.

Follow this decision tree to pick the right loop. Start at the top and answer each question. Most everyday tasks land on for...of; switch to an index-based loop when you need to traverse backward or skip elements by a custom step.

Common Variations

Common loop patterns and their ideal use cases
PatternCodeWhen to Use
Forward (standard)for (let i = 0; i < arr.length; i++)Default index-based pattern; most common
Backwardfor (let i = arr.length - 1; i >= 0; i--)Reversing output, removing items while iterating
Skip by 2for (let i = 0; i < arr.length; i += 2)Processing every other element (e.g., even indices)
for...of (values)for (const val of arr)Simple iteration, no index needed
for...of + entriesfor (const [i, val] of arr.entries())Need both index and value with cleaner syntax

Worked Example — Finding the Highest Score

Suppose you have an array of quiz scores and you need to find the highest score along with which quiz number it belongs to. We will solve this with both loop styles so you can see the difference in practice.

Solution A — Index-Based for Loop
1
Step 1 — Set Up the DataWe start by declaring the array and initializing two tracking variables: let highScore = scores[0]; and let bestQuiz = 0;. We assume the first element is the highest until proven otherwise.
const scores = [78, 92, 85, 96, 88];
2
Step 2 — Write the LoopWe start i at 1 (since we already used index 0). On each iteration we compare scores[i] to highScore. If the current score is larger, we update both highScore and bestQuiz.
for (let i = 1; i < scores.length; i++) { if (scores[i] > highScore) { highScore = scores[i]; bestQuiz = i; } }
3
Step 3 — Trace the Executioni=1: 92 > 78 → update to 92, bestQuiz=1. i=2: 85 > 92? No. i=3: 96 > 92 → update to 96, bestQuiz=3. i=4: 88 > 96? No. Loop ends.
highScore = 96, bestQuiz = 3
Solution B — for...of with entries()
1
Step 1 — Same Data, Different LoopWe use for (const [i, score] of scores.entries()) to get both the index and the value in a single, readable line. The destructuring [i, score] automatically splits each pair.
for (const [i, score] of scores.entries()) { if (score > highScore) { highScore = score; bestQuiz = i; } }
2
Step 2 — Compare the Two ApproachesBoth produce the exact same result. The for...of version avoids the scores[i] bracket syntax and eliminates the manual increment. However, the index-based version lets us start at index 1 directly, which is slightly more efficient since it skips one comparison.
Same result: highScore = 96 at quiz 3

Strengths & Limitations

Neither loop style is universally better. Each shines in specific situations. The table below breaks down the key differences to help you make an informed choice every time you write a loop.

Feature comparison between the two loop styles
FeatureIndex-Based forfor...of
ReadabilityMore verbose — three-part headerCleaner — reads almost like English
Index accessBuilt in — just use iRequires .entries()
Backward iterationEasy — just change init and updateNot directly supported
Custom step sizeEasy — i += 2, etc.Not supported
break / continueFully supportedFully supported
Off-by-one errorsCommon riskEliminated
Works with non-arraysOnly array-like objects with .lengthAny iterable (strings, Maps, Sets)
✦ KEY TAKEAWAY
Think of it like choosing between a manual and automatic car. The index-based for loop is the manual transmission — more control, but you can stall if you make a mistake with the clutch (off-by-one error). The for...of loop is the automatic — smoother for everyday driving, though you cannot manually shift into reverse on command. Use the right tool for the job.

Connection to Advanced Iteration

The loops you have learned in this lesson form the foundation for more advanced iteration patterns you will encounter as you grow as a developer. JavaScript's array methods like .map(), .filter(), and .reduce() build on the same concept of visiting each element but wrap the loop in a function call. Understanding the raw loops first makes those higher-order methods much easier to grasp.

How basic loops connect to advanced array methods
Concept You Know NowAdvanced VersionKey Difference
for...of over arraysfor...of over generatorsGenerators produce values lazily, on demand, instead of storing them all in memory
Index-based loop with break.find() / .findIndex()Returns the first matching element or index without manual break logic
Loop that builds a new array.map()Returns a transformed copy of the array in a single expression
Loop that filters elements.filter()Returns a new array with only the elements that pass a test function
Loop that accumulates a total.reduce()Combines all elements into a single result (sum, object, etc.)

Another important concept is asynchronous iteration. In future courses, you may encounter for await...of, which works like for...of but handles data that arrives over time (like streaming data from a server). Mastering synchronous loops now prepares you to understand that async pattern later.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Explain in your own words the main difference between a for...of loop and an index-based for loop. When would you prefer one over the other?
PROBLEM 2 — BASIC CALCULATION
Given const temps = [72, 68, 75, 80, 77];, write a for...of loop that calculates and logs the sum of all temperatures. What will the sum be?
PROBLEM 3 — INTERMEDIATE
Given const words = ["hello", "world", "foo", "bar", "javascript"];, use an index-based for loop to build a new array containing only the words that have more than 3 characters. Store the result in a variable called longWords. What does longWords contain?
PROBLEM 4 — APPLIED
A teacher stores grades in const grades = [88, 45, 92, 73, 61, 55, 97];. Using for...of with .entries(), write code that logs the index and grade of every student who scored below 60. Use continue to skip students who passed.
PROBLEM 5 — CRITICAL THINKING
Consider this code: const data = [10, 20, 30, 40, 50]; for (let i = 0; i <= data.length; i++) { console.log(data[i] * 2); } There is a bug. Identify it, explain what output this produces, and fix the code using (a) an index-based loop and (b) a for...of loop.

Lesson Summary

JavaScript provides two primary ways to iterate arrays. The index-based for loop uses three parts — initialization, condition, and update — to manually control a counter variable. It excels when you need the index, want to iterate backward, or need a custom step size. However, it carries the risk of off-by-one errors if the condition uses <= instead of <.

The for...of loop, introduced in ES6 (2015), iterates directly over values using the iterator protocol. It is cleaner, safer, and works on any iterable — arrays, strings, Maps, and Sets. When you need both the index and the value, combine it with .entries(). Both loops support break and continue for full control over the iteration process. Mastering these patterns prepares you for higher-order array methods like .map(), .filter(), and .reduce().

Varsity Tutors • JavaScript • for...of & Index Loops