Loops: doing it again
You have eleven players and you want to print each name. You could write
eleven console.log lines, and then the squad changes and you rewrite them
all. A loop says the instruction once and applies it to every item.
let players = ["Babar", "Rizwan", "Shaheen"];
for (const player of players) {
console.log(player);
}
Babar Rizwan Shaheen
Three names, one instruction, and it works just as well with three hundred.
for...of is the one to reach for
for...of walks through the items of an array and hands you each one in turn.
There is no counting and no index arithmetic, which removes the whole class of
bug in the next section.
let prices = [250, 120, 80];
let total = 0;
for (const price of prices) {
total = total + price;
}
console.log(total);
450
const inside the loop is correct even though the value changes each time
round. Each pass creates a fresh player or price; nothing is reassigned.
It works on strings too, since a string is a sequence of characters:
for (const letter of "chai") {
console.log(letter);
}
c h a i
The classic for loop
When you need the position — numbering a list, or comparing an item to the one before it — the counting loop earns its keep.
let players = ["Babar", "Rizwan", "Shaheen"];
for (let i = 0; i < players.length; i++) {
console.log(`${i + 1}. ${players[i]}`);
}
1. Babar 2. Rizwan 3. Shaheen
The three parts inside the brackets, separated by semicolons:
let i = 0— where to start. Arrays begin at 0, so counters do too.i < players.length— keep going while this is true.i++— what to do after each pass.
i is the conventional name and it stands for index. Use let, not const,
because it genuinely is reassigned each time.
The off-by-one error
The condition is where this loop goes wrong, and it goes wrong in exactly two ways.
let players = ["Babar", "Rizwan", "Shaheen"];
for (let i = 0; i < players.length - 1; i++) {
console.log(players[i]);
}
Babar Rizwan
Shaheen never gets printed. The array has 3 items at positions 0, 1 and 2;
length - 1 is 2, and i < 2 stops at 1. The - 1 looks like it is
compensating for zero-based counting, and it is compensating for something
that < already handled.
The opposite mistake runs one too far:
let players = ["Babar", "Rizwan", "Shaheen"];
for (let i = 0; i <= players.length; i++) {
console.log(players[i]);
}
Babar Rizwan Shaheen undefined
i <= 3 includes position 3, which does not exist, so JavaScript hands back
undefined rather than raising an error. In a real program that undefined
flows onward and breaks something far away.
The correct form is i = 0; i < length; i++, with a strict less-than and
no arithmetic. Write it as one unit and do not improvise. Better still, use
for...of when you do not need i, and the question never comes up.
while, for when you cannot count in advance
while repeats as long as a condition holds. It suits situations where the
number of passes is not known when the loop starts.
let seatsLeft = 3;
while (seatsLeft > 0) {
console.log(`Seat sold, ${seatsLeft - 1} left`);
seatsLeft = seatsLeft - 1;
}
Seat sold, 2 left Seat sold, 1 left Seat sold, 0 left
The danger is obvious once stated: something inside the loop must eventually make the condition false. Forget that line and the loop runs forever, the page freezes, and the tab has to be closed. Before writing the body, write the line that changes the condition.
break and continue
break leaves the loop immediately. continue skips the rest of this pass
and starts the next one.
let marks = [72, 45, 88, 30, 91];
for (const mark of marks) {
if (mark < 50) {
continue;
}
console.log(mark);
}
72 88 91
let marks = [72, 45, 88, 30, 91];
for (const mark of marks) {
if (mark > 85) {
console.log(`First distinction: ${mark}`);
break;
}
}
First distinction: 88
break is how you stop once you have found what you were looking for. Without
it, the loop keeps checking every remaining item for no reason — and would
print 91 as well.
Loops inside loops
The inner loop runs completely for every single pass of the outer one.
let sizes = ["small", "large"];
let drinks = ["chai", "coffee"];
for (const size of sizes) {
for (const drink of drinks) {
console.log(`${size} ${drink}`);
}
}
small chai small coffee large chai large coffee
Two lists of two give four lines. That multiplication is the thing to watch: two lists of a thousand give a million passes, and a page that stops responding. Nesting is fine for small, known lists and worth rethinking for large ones.
Looping over an object
for...of does not work on plain objects, because an object is not a sequence.
Object.entries turns it into one:
let stock = { chai: 12, coffee: 4, lassi: 0 };
for (const [item, count] of Object.entries(stock)) {
console.log(`${item}: ${count}`);
}
chai: 12 coffee: 4 lassi: 0
Object.keys and Object.values give just one side each. There is also
for...in, which loops over keys — it behaves surprisingly with inherited
properties, and Object.keys is the safer habit.
The array methods that replace loops
Much of what loops are used for has a shorter form. forEach runs a function
for each item; map builds a new array from the results; filter keeps the
items that pass a test.
let prices = [250, 120, 80];
let withTax = prices.map(price => Math.round(price * 1.15));
let cheap = prices.filter(price => price < 200);
console.log(withTax);
console.log(cheap);
console.log(prices.reduce((sum, price) => sum + price, 0));
[ 288, 138, 92 ] [ 120, 80 ] 450
Each of those is a loop underneath, with the counting hidden and the intent
visible in the name. They get a lesson of their own; for now it is enough to
know that when you find yourself writing a for loop that builds a new array,
map probably says it in one line.
Which loop to use
- Every item, no index needed →
for...of. This is most of the time. - You need the position →
for (let i = 0; i < n; i++). - Unknown number of passes →
while, with the exit line written first. - Building a new array, or a total →
map,filter,reduce.
And whenever you reach for the counting loop, write the condition as
i < length. Strictly less than, no arithmetic. That single habit removes the
most common loop bug there is.
Prefer learning with a teacher?
WasiLearn Academy runs small-group classes covering this material, online and in Karachi.
See the classes