Learning path · Level 4 · Tutorial 5

Process Collections with JavaScript Loops

Use loops to process collections and repeat calculations while keeping iteration boundaries and termination explicit.

  • Level: Beginner
  • Duration: 18 min
  • 7 steps
Start tutorial Back to the path
Process Collections with JavaScript Loops

Step 1 of 7

Visit Array Values with for...of

Use for...of to perform one operation on each product in array order.

Follow the array order

One value per iteration

for...of visits the values in an array one at a time, in the array's existing order. Each pass is an iteration: JavaScript gives the loop body the current value, then moves to the next value.

In for (const product of products), product is the current product record. You can read product.name during that iteration without changing the source array. No explicit index is needed when the value itself is all you need.

A diagram shows three product records visited from left to right, with each record connected to one console output line.

The loop body runs once per record: Notebook produces the first line, Pen the second, and Folder the third.

See the traversal in the console

Run a complete local example

Use your familiar edit-save-refresh workflow. Keep these two local files together. Replace the complete contents of loops.js with the script shown, refresh index.html in the browser, and open the console.

The loop body logs one name for each current product. Reading .name does not modify any record.

index.html

index.html

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Product Loop</title>
  <script src="loops.js" defer></script>
</head>
<body>
  <h1>Product Loop</h1>
  <p>Open the browser console to view results.</p>
</body>
</html>

loops.js

loops.js

javascript
const products = [{ name: "Notebook", stock: 3 }, { name: "Pen", stock: 0 }, { name: "Folder", stock: 5 }];

for (const product of products) {
  console.log(product.name);
}
Expected output
Notebook
Pen
Folder

These three lines appear in the browser console, in this order.

Check your traversal

Complete and predict

Complete the full for...of header and the current-value property access. Then fill the final three blanks with the console order for the shared products collection.

javascript
 {
  console.log(.);
}

// Console order:  →  → 

Step 2 of 7

Build a Summary with Accumulators

Build a reusable stock summary by preserving running values across a for...of traversal.

Start fresh, then accumulate

Keep running results

An accumulator is a local variable that keeps a running result as iterations happen. For a stock summary, one accumulator adds every product.stock; another counts only records whose stock is greater than zero.

Create both inside summarizeStock(products), before the loop. Each function call then starts with fresh values instead of reusing a result from an earlier call.

Two accumulators across a traversal

A traversal of three product records updates a total accumulator for every record and a count accumulator only for records with positive stock.

Every iteration updates totalStock; only a positive stock value updates stockedProducts.

Trace all iterations

Trace the running values

Trace the loop body one product at a time. totalStock changes on every iteration. stockedProducts changes only when the if condition is true.

Accumulator trace

The state after each iteration of the shared collection.

The completed summary is formed only after all three iterations.
Current recordStocktotalStockstockedProducts
Before the loop—00
Notebook331
Pen031
Folder582

Tip

Finish before returning

Put return after the loop. Returning from inside the loop body would end the function during its first iteration, before the remaining records can update the accumulators.

Run a reusable summary function

index.html

Use this local index.html file to load your script.

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Stock Summary</title>
    <script src="loops.js" defer></script>
  </head>
  <body>
  </body>
</html>

loops.js

Replace the contents of loops.js with this complete script. Save, refresh the page, and inspect the browser console.

javascript
const products = [{ name: "Notebook", stock: 3 }, { name: "Pen", stock: 0 }, { name: "Folder", stock: 5 }];

function summarizeStock(products) {
  let totalStock = 0;
  let stockedProducts = 0;

  for (const product of products) {
    totalStock = totalStock + product.stock;

    if (product.stock > 0) {
      stockedProducts = stockedProducts + 1;
    }
  }

  return { totalStock: totalStock, stockedProducts: stockedProducts };
}

const summary = summarizeStock(products);
console.log("totalStock:", summary.totalStock);
console.log("stockedProducts:", summary.stockedProducts);
Expected output
totalStock: 8
stockedProducts: 2

The labels make the two final values easy to compare in the console.

Practice: complete the calculation

Build the complete summary

Complete the summary function, then run it locally to verify both summary values.

javascript
const products = [{ name: "Notebook", stock: 3 }, { name: "Pen", stock: 0 }, { name: "Folder", stock: 5 }];

function summarizeStock(products) {
  let totalStock = ;
  let stockedProducts = ;

  for (const product of products) {
    totalStock = totalStock + ;

    if () {
      stockedProducts = stockedProducts + ;
    }
  }

  return ;
}

const summary = summarizeStock(products);
console.log("totalStock:", summary.totalStock);
console.log("stockedProducts:", summary.stockedProducts);

Step 3 of 7

Control an Index with for

Write and trace an indexed for loop that processes every array position exactly once.

Make the index explicit

A loop header controls the index

Use an indexed for loop when the position matters as well as the current value. Its header keeps three controls together:

  • initialization: let i = 0 runs once;
  • continuation condition: i < products.length is checked before each iteration;
  • update: i = i + 1 runs after each loop body.

Inside the body, products[i] reads the product at the current position. The loop does not change the array.

Index traversal through an array

A diagram showing an index moving from 0 to 2 across three product records, then stopping at the boundary after the last record.

The index selects one existing array position per iteration. The continuation condition prevents the loop body from running for the first position beyond the array.

Run and trace the indexed loop

Trace one complete loop

The execution order is always: initialization once, condition check, loop body, update, then another condition check. If the condition is false, the loop body does not run.

Here, products.length is 3. The condition permits i values 0, 1, and 2; after the final update, i is 3, so the loop ends before an invalid array position is read.

loops.js: log each index and name

Replace your entire loops.js with this code. Save the file, refresh your existing local page, and inspect the browser console.

javascript
const products = [
  { name: "Notebook", stock: 3 },
  { name: "Pen", stock: 0 },
  { name: "Folder", stock: 5 }
];

for (let i = 0; i < products.length; i = i + 1) {
  const product = products[i];
  console.log("Index " + i + ": " + product.name);
}
Expected output
Index 0: Notebook
Index 1: Pen
Index 2: Folder

The important pattern is one console line for each existing index, in array order.

Short trace

Follow the values through the condition and loop body.

The body runs only while the continuation condition is true.
Condition checkCurrent productConsole output
i = 0, trueNotebookIndex 0: Notebook
i = 1, truePenIndex 1: Pen
i = 2, trueFolderIndex 2: Folder
i = 3, falseNo product readLoop ends

Check the execution sequence

Order the loop stages

Put the stages of an indexed for loop in their execution order for its first iteration.

  1. Run the loop body with `products[i]`.
  2. Update `i` with `i = i + 1`.
  3. Check whether `i < products.length`.
  4. Initialize `i` to `0`.

Apply the indexed loop

Build the indexed traversal

Complete the indexed loop so it logs indexes 0, 1, and 2 with their corresponding product names.

javascript
const products = [
  { name: "Notebook", stock: 3 },
  { name: "Pen", stock: 0 },
  { name: "Folder", stock: 5 }
];

for () {
  const product = ;
  console.log("Index " + i + ": " + product.name);
}

Step 4 of 7

Check Boundaries and Empty Collections

Repair indexed-loop boundaries and predict the results for empty and single-element collections.

Identify valid indexes

Keep the boundary outside the array

An off-by-one error makes a loop visit one position too many or skip a position it needs. For an array of length 3, the permitted indexes are 0, 1, and 2. The value 3 is the first index outside the array.

With an indexed loop, i < products.length checks that i is still a permitted index before the loop body runs. Starting with i = 1 is not a boundary fix: it skips the first record at index 0.

Valid positions and the stopping boundary

A three-record array has valid indexes 0, 1, and 2; the next position is shown beyond a stopping boundary.

The condition is checked before each iteration. The loop body can use indexes from 0 through products.length - 1, but not products.length itself.

Boundary checklist

Use these small collections to check both boundaries and summary results.

Expected behavior with the standard indexed loop and a summary initialized to zero.
CollectionLengthIterationstotalStockstockedProducts
[]0000
[products[0]]1131
products3382

Run boundary cases locally

Check summaries at both boundaries

Run this complete local example. It checks the shared collection plus an empty collection and a one-record collection. An empty array never enters the loop body, so the initial accumulator values are returned unchanged.

index.html

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Loop Boundaries</title>
    <script src="loops.js" defer></script>
  </head>
  <body>
    <h1>Loop Boundaries</h1>
  </body>
</html>

loops.js

javascript
const products = [{ name: "Notebook", stock: 3 }, { name: "Pen", stock: 0 }, { name: "Folder", stock: 5 }];

function summarizeStock(products) {
  let totalStock = 0;
  let stockedProducts = 0;

  for (let i = 0; i < products.length; i = i + 1) {
    const product = products[i];
    totalStock = totalStock + product.stock;

    if (product.stock > 0) {
      stockedProducts = stockedProducts + 1;
    }
  }

  return { totalStock: totalStock, stockedProducts: stockedProducts };
}

const emptySummary = summarizeStock([]);
const singleSummary = summarizeStock([products[0]]);
const allSummary = summarizeStock(products);

console.log("Empty: totalStock=" + emptySummary.totalStock + ", stockedProducts=" + emptySummary.stockedProducts);
console.log("Single: totalStock=" + singleSummary.totalStock + ", stockedProducts=" + singleSummary.stockedProducts);
console.log("All: totalStock=" + allSummary.totalStock + ", stockedProducts=" + allSummary.stockedProducts);
Expected output
Empty: totalStock=0, stockedProducts=0
Single: totalStock=3, stockedProducts=1
All: totalStock=8, stockedProducts=2

The three lines appear in the browser console after you save both files and refresh the page.

Fix the extra iteration

Repair the continuation condition

Replace the incorrect comparison so this loop visits only valid array positions.

javascript
const products = [{ name: "Notebook", stock: 3 }, { name: "Pen", stock: 0 }, { name: "Folder", stock: 5 }];

for (let i = 0; i  products.length; i = i + 1) {
  const product = products[i];
  console.log(product.name);
}

Verify your loop choice

Apply the boundary check

Without running code, write a short boundary check. Include: the corrected indexed for header; whether a loop that starts at index 1 is acceptable and why; and the iteration count plus totalStock and stockedProducts for [] and [products[0]].

Write at least 80 characters (0/80).

Step 5 of 7

Repeat While a Condition Holds

Use changing state to control a terminating while loop, and inspect loop progress before running suspicious code.

Model a while loop

Condition-controlled repetition

A while loop repeats because a continuation condition is true. Before every iteration, JavaScript checks that condition. If it is false at the first check, the loop body runs zero times.

Use while when changing state controls repetition. Unlike for...of, it does not automatically visit array values. You must create the state before the loop and change it in the loop body so it can reach a stopping point.

Trace the changing state

A flow diagram showing a value decreasing from 3 to 0, then stopping.

The condition is checked before each iteration. Values 3, 2, and 1 enter the loop body; value 0 stops it.

Initialize, test, and update

Run a finite while loop

Create or replace loops.js with this complete script. In your existing index.html, keep the deferred connection to loops.js. This loop processes units represented by remaining; it does not modify products.

The initialization is before the loop. Each iteration logs the current state, then the update moves that state toward termination.

loops.js

Save as loops.js, then refresh the browser and inspect the console.

javascript
const products = [
  { name: "Notebook", stock: 3 },
  { name: "Pen", stock: 0 },
  { name: "Folder", stock: 5 }
];

let remaining = 3;

while (remaining > 0) {
  console.log("Units remaining: " + remaining);
  remaining = remaining - 1;
}

console.log("Finished processing units.");
Expected output
Units remaining: 3
Units remaining: 2
Units remaining: 1
Finished processing units.

The important result is that the last logged unit count is 1; the loop does not log a count of 0.

Check progress before running

Prove that progress exists

Termination depends on a path from the starting state to a false continuation condition. Here, subtracting one moves remaining from 3 to 2, then 1, then 0. At 0, remaining > 0 is false, so JavaScript skips the loop body.

Before running a new while loop, trace at least a few state changes on paper or in your head.

Warning

Avoid non-terminating loops

Do not run this variant. Its update moves remaining away from the stopping point, so a positive starting value stays positive indefinitely. A missing update can cause the same problem. Inspect suspicious loops by tracing their state rather than letting the browser run forever.

A state change in the wrong direction

Diagnostic example only — do not save or run this code.

javascript
let remaining = 3;

while (remaining > 0) {
  remaining = remaining + 1;
}

Check your while-loop reasoning

Complete the terminating loop

Complete the continuation condition and the progress update.

javascript
const products = [
  { name: "Notebook", stock: 3 },
  { name: "Pen", stock: 0 },
  { name: "Folder", stock: 5 }
];

let remaining = 3;

while () {
  console.log("Units remaining: " + remaining);
  
}

Predict the boundary case

Set remaining to 0 immediately before the same loop. What happens?

Identify the non-terminating variant

A loop starts with 3 units remaining. It continues while the value is positive, but every iteration adds 1 to the remaining value. Which description is correct?

Step 6 of 7

Stop Early with break

Use break to end a collection search at its first matching record while preserving a clear null result when no match exists.

Understand the early stop

Save, then stop

A search needs a result even when no record matches. In firstOutOfStockName(products), begin with outOfStockName set to null.

Each iteration checks one product. When product.stock === 0, first save product.name in the result variable. Then use break to exit the current loop immediately. Code after the loop still runs, so the function returns the saved result after traversal stops.

If no product has zero stock, the loop ends normally and the result remains null. An empty collection also performs zero iterations and returns null.

Early-stop traversal

A traversal visits the Notebook and then the zero-stock Pen, stops there, and leaves the Folder unvisited.

The match is saved at the zero-stock record before break ends the loop. Records after that match are not visited.

Run a complete search function

Run the search locally

Create or replace these local files, save them, refresh index.html, and inspect the browser console. The script searches the shared collection, a collection with no zero-stock record, and an empty collection. It does not change any product record.

index.html

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Loop Search</title>
  <script src="loops.js" defer></script>
</head>
<body>
  <h1>Loop Search</h1>
</body>
</html>

loops.js

javascript
const products = [{ name: "Notebook", stock: 3 }, { name: "Pen", stock: 0 }, { name: "Folder", stock: 5 }];

function firstOutOfStockName(products) {
  let outOfStockName = null;

  for (const product of products) {
    if (product.stock === 0) {
      outOfStockName = product.name;
      break;
    }
  }

  return outOfStockName;
}

console.log("First out of stock:", firstOutOfStockName(products));
console.log("No out of stock:", firstOutOfStockName([products[0], products[2]]));
console.log("Empty collection:", firstOutOfStockName([]));
Expected output
First out of stock: Pen
No out of stock: null
Empty collection: null

The important difference is that the shared collection stops at its first zero-stock record, while the other two calls finish without a match.

Practice the statement order

Complete the match branch

Complete the two statements in the match branch.

javascript
function firstOutOfStockName(products) {
  let outOfStockName = null;

  for (const product of products) {
    if (product.stock === 0) {
      
      
    }
  }

  return outOfStockName;
}

Verify normal and no-match behavior

Predict the search results

After the function is completed correctly, which outcome describes both searches?

Step 7 of 7

Apply and Verify Your Loop Choices

Choose suitable loop forms and verify a complete collection-processing solution against normal and boundary cases.

Select deliberately

Choose by the source of control

Choose the loop form by asking what controls repetition:

  • Use for...of when you need each array value and its existing order.
  • Use for when an explicit index or counter is central to the task.
  • Use while when changing state controls whether another iteration happens.

Before you run any loop, check five things: the starting state, the continuation condition, the progress update, required boundaries such as an empty array, and any early-stop condition. A loop can sometimes be written in more than one form; prefer the form that makes its control most visible.

Three ways to control repetition

A diagram contrasts value-by-value array traversal, indexed traversal, and repetition controlled by a changing counter.

Array values suggest for...of; positions suggest for; changing state suggests while.

Quick loop-choice guide

Use this guide when selecting a loop. The final check applies regardless of the chosen form.

Loop form follows the information that controls the next iteration.
Task focusPreferWhy
Current array value`for...of`No explicit index is needed
Array position or counter`for`Initialization, continuation condition, and update are visible
Changing state`while`The continuation condition is checked before each iteration
First matching value`for...of` + `break`Stop immediately after saving the first match

Practice loop selection

Match the task to the loop

Match each task to the loop form that makes its control clearest.

Tap an item and then its matching pair.

Apply the two collection functions

Complete the summary and early-stop search

Complete the two functions. Keep the source collection unchanged, make the summary cover every product, and stop the search at its first zero-stock product.

javascript
const products = [
  { name: "Notebook", stock: 3 },
  { name: "Pen", stock: 0 },
  { name: "Folder", stock: 5 }
];

function summarizeStock(products) {
  let totalStock = 0;
  let stockedProducts = 0;

  for (const product of products) {
    
    if () {
      
    }
  }

  return { totalStock: totalStock, stockedProducts: stockedProducts };
}

function firstOutOfStockName(products) {
  let outOfStockName = null;

  for (const product of products) {
    if () {
      
      
    }
  }

  return outOfStockName;
}

Verify normal and boundary cases

Run a local verification

Create or confirm these two local files. Then replace the complete contents of loops.js with the verification script on this screen. Save both files, open or refresh index.html, and inspect the browser console.

Local page

index.html

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Loop verification</title>
    <script src="loops.js" defer></script>
  </head>
  <body>
    <h1>Loop verification</h1>
  </body>
</html>

Complete verification script

loops.js

javascript
const products = [
  { name: "Notebook", stock: 3 },
  { name: "Pen", stock: 0 },
  { name: "Folder", stock: 5 }
];

function summarizeStock(products) {
  let totalStock = 0;
  let stockedProducts = 0;

  for (const product of products) {
    totalStock = totalStock + product.stock;
    if (product.stock > 0) {
      stockedProducts = stockedProducts + 1;
    }
  }

  return { totalStock: totalStock, stockedProducts: stockedProducts };
}

function firstOutOfStockName(products) {
  let outOfStockName = null;

  for (const product of products) {
    if (product.stock === 0) {
      outOfStockName = product.name;
      break;
    }
  }

  return outOfStockName;
}

const sharedSummary = summarizeStock(products);
const emptySummary = summarizeStock([]);
const singleSummary = summarizeStock([products[0]]);
const emptyOutOfStockName = firstOutOfStockName([]);
const noOutOfStockName = firstOutOfStockName([products[0], products[2]]);

console.log("Shared totalStock:", sharedSummary.totalStock);
console.log("Shared stockedProducts:", sharedSummary.stockedProducts);
console.log("Shared first out-of-stock name:", firstOutOfStockName(products));
console.log("Empty totalStock:", emptySummary.totalStock);
console.log("Empty stockedProducts:", emptySummary.stockedProducts);
console.log("Empty first out-of-stock name:", emptyOutOfStockName);
console.log("Single totalStock:", singleSummary.totalStock);
console.log("Single stockedProducts:", singleSummary.stockedProducts);
console.log("No-out-of-stock name:", noOutOfStockName);
Expected output
Shared totalStock: 8
Shared stockedProducts: 2
Shared first out-of-stock name: Pen
Empty totalStock: 0
Empty stockedProducts: 0
Empty first out-of-stock name: null
Single totalStock: 3
Single stockedProducts: 1
No-out-of-stock name: null

Console spacing and styling can differ slightly by browser; the labels and values should match.

Report and conclude

Final verification report

After running the script, report:

  1. The shared collection's totalStock, stockedProducts, and first out-of-stock name.
  2. All three results for the empty collection.
  3. The single-product total and count, plus the no-match search result.
  4. One sentence naming a boundary or termination check in the script and what it prevents.

Do not paste code; report the observed values and your reasoning.

Write at least 100 characters (0/100).

Step complete

Congratulations! You completed: Process Collections with JavaScript Loops

Verified loops make repetition, termination, and collection boundaries explicit.

Download the App now to have access to + 5000 free courses, exercises, certificates and lots of content without paying anything!

  • 100% free online courses from start to finish

    Thousands of online courses in video, ebooks and audiobooks.

  • More than 60 thousand free exercises

    To test your knowledge during online courses

  • Valid free Digital Certificate with QR Code

    Generated directly from your cell phone's photo gallery and sent to your email

Cursa app on the ebook screen, the video course screen and the course exercises screen, plus the course completion certificate