The classic for (let i = 0; i < n; i++) loop from the for loops lesson can do anything, but most of the time you don't actually need the counter. You just want each item of an array, each letter of a word, or each key of an object. JavaScript has two shorter loops for exactly that: for...of for values and for...in for keys.
You also often need to change a loop's course partway through. When you find the item you were searching for, there's no point checking the rest, so you break out of the loop. When an item is invalid, you want to continue with the next one instead of stopping completely.
In this lesson you'll learn when to use for...of and for...in, the common mistake that mixes them up, how break and continue work in every kind of loop, how labels let you break out of nested loops, and how these loops compare with array methods such as forEach.
for...of: loop over values
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}for...ofgives you each value in turn.- It works with anything iterable: arrays, strings, Sets, Maps, NodeLists from
querySelectorAll, and more. - Use
constfor the loop variable unless you need to reassign it inside the loop. - Need the index too? Use
for (const [i, fruit] of fruits.entries()).
for...in: loop over object keys
const prices = { tea: 2.2, coffee: 2.8, cake: 3.5 };
for (const item in prices) {
console.log(item, prices[item]);
}for...ingives you each key (property name) of an object as a string.- Read the value with square brackets:
prices[item]. - Avoid
for...inon arrays. It gives indexes as strings, can include extra properties, and isn't guaranteed to be in order in older code. - A modern alternative is
for (const [key, value] of Object.entries(obj)).
break and continue
| Statement | What it does |
|---|---|
break | Stops the loop completely and jumps to the code after it |
continue | Skips the rest of this iteration and moves to the next one |
Both work in for, for...of, for...in, while and do...while loops. break also ends a switch case. When loops are nested, break and continue only affect the innermost loop. To stop an outer loop, put a label in front of it and write break outer;.
Loops vs array methods
| Need | Loop | Array method |
|---|---|---|
| Do something with each item | for...of | forEach |
| Stop early when found | for...of with break | find, some, findIndex |
| Build a new array | push inside a loop | map, filter |
Use await inside | for...of works | forEach doesn't wait |
forEach can't be stopped with break. If you need to stop early, use for...of or a method like find. You'll see more methods in array methods.
JavaScript Loop Control Syntax
Loop control
for (const item of array) { }
for (const char of "hello") { }
for (const [i, item] of array.entries()) { }
for (const key in object) { console.log(key, object[key]); }
for (const [key, value] of Object.entries(object)) { }
for (const n of nums) {
if (n < 0) continue; // skip negatives
if (n > 100) break; // stop completely
}JavaScript Loop Control Summary
for...ofloops over values of arrays, strings, Sets, Maps and NodeLists.for...inloops over the keys of an object; avoid it for arrays.breakstops a loop;continueskips to the next iteration.- Labels let
breakandcontinuetarget an outer loop. forEachcan't be stopped early, so usefor...oforfindwhen you need to.
JavaScript Loop Control Examples
Each example runs in the page. Edit the code and press Run to see what changes.
for...of with arrays and strings
const scores = [72, 95, 58, 88];
let total = 0;
for (const score of scores) {
total += score;
}
console.log("Average:", total / scores.length);
for (const [i, score] of scores.entries()) {
console.log(`Test ${i + 1}: ${score}`);
}
let vowels = 0;
for (const letter of "javascript") {
if ("aeiou".includes(letter)) vowels++;
}
console.log("Vowels:", vowels);Line-by-line explanation
- Lines 3 to 5Each score is added to the total without needing an index.
- Line 8
entries()gives the index and the value together. - Line 13Strings are iterable, so
for...ofgives each letter.
for...in with an object
const stock = { apples: 12, pears: 0, plums: 7 };
for (const fruit in stock) {
console.log(`${fruit}: ${stock[fruit]}`);
}
for (const [fruit, count] of Object.entries(stock)) {
if (count === 0) console.log(`Reorder ${fruit}`);
}Line-by-line explanation
- Lines 3 to 4
fruitis each key;stock[fruit]reads the value. - Line 7
Object.entrieswithfor...ofgives key and value pairs, which is often clearer.
break, continue and labels
const orders = [12, -1, 30, 0, 999, 45];
for (const amount of orders) {
if (amount <= 0) {
console.log("skip invalid", amount);
continue;
}
if (amount > 500) {
console.log("suspicious order, stopping");
break;
}
console.log("process", amount);
}
const grid = [[1, 2], [3, 4], [5, 6]];
search: for (const row of grid) {
for (const cell of row) {
if (cell === 4) {
console.log("found 4");
break search;
}
}
}Line-by-line explanation
- Lines 4 to 7Invalid amounts are skipped and the loop carries on.
- Lines 8 to 11A suspicious order stops the loop; 45 is never processed.
- Line 16The label names the outer loop.
- Line 20
break searchleaves both loops at once.
Common JavaScript Loop Control Mistakes
for...in on an array
for (const i in ["a", "b"]) {
console.log(i + 1); // "01", "11": i is a string
}for (const [i, letter] of ["a", "b"].entries()) {
console.log(i + 1, letter);
}for...of on a plain object
for (const value of { a: 1, b: 2 }) { } // TypeError: not iterablefor (const value of Object.values({ a: 1, b: 2 })) { }Trying to break out of forEach
items.forEach(item => {
if (item === target) break; // SyntaxError
});for (const item of items) {
if (item === target) break;
}JavaScript Loop Control in Real Projects
Loops in real code
Shopping carts loop over items with for...of to total prices. Settings pages loop over object keys to build form fields. Search code uses break to stop once a match is found, and data import scripts use continue to skip blank or invalid rows instead of failing the whole file. DOM code loops over querySelectorAll results with for...of.
JavaScript Loop Control Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Loop over each colour's value.
const colours = ["red", "green", "blue"];
for (const colour colours) {
console.log(colour);
}
for...of gives values.What is logged?
for (const n of [1, 2, 3, 4, 5]) {
if (n === 2) continue;
if (n === 4) break;
console.log(n);
}What does for...in give you for an object?
Which loop can you stop early with break?
firstNegative should return the first negative number in the array, or null if there isn't one. Fix it.
function firstNegative(nums) {
let found = null;
for (const i in nums) {
if (nums[i] < 0) {
found = i;
continue;
}
}
return found;
}
console.log(firstNegative([4, -2, 7, -9]));- Returns the first negative value
- Returns null when there is none
- Works when the first item is negative
JavaScript Loop Control Quiz
5 questions to check what you learned.
Which loop is best for the values of an array?
- for...in
- for...of
- do...while
- switch
What does continue do?
- Skips to the next iteration
- Ends the program
- Restarts the loop from the beginning
- Exits all loops
How do you get index and value in a for...of loop?
- for (const i, v of arr)
- for (const v in arr)
- arr.indexOf inside the loop
- for (const [i, v] of arr.entries())
Which of these is NOT iterable with for...of?
- A plain object
- A string
- A Set
- A NodeList
In nested loops, what does a plain break affect?
- All loops
- The outer loop
- Only the innermost loop
- Nothing
JavaScript Loop Control Challenge
Stock checker
Write checkStock(stock, limit):
- Loop over the keys of
stock(an object like{ tea: 3, milk: 0 }) - Skip items with a count of
0usingcontinue - Collect the names of items with a count below
limitinto an array - Stop the loop with
breakonce the array has 3 names - Return the array
function checkStock(stock, limit) {
}
console.log(checkStock({ tea: 3, milk: 0, sugar: 1, cups: 9, lids: 2, bags: 1 }, 5));- Finds low items, skipping zero
- Stops at three names
- Uses continue and break