Introduction
Loops are the last of the major language features in Javascript that we’ll be covering. Now that we’ve grasped statements, variables and their types, functions, arrays and objects this last piece will give us eveything we need to solve procedural problems.
As always, MDN’s documentation is very good: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration
I’ve tried to give a “whys” outline below, where MDN offer more of a “how”. So it is worth reading both.
Why Loop?
On the web, we write programs and applications to solve a problem or achieve a goal. Most of these programs eventually come down to shovelling data about in some form or another. We may need to capture someones information to deliver a product, or sell to an advertiser. Or we may need to take user input so that we may determine which of our hilarious cat videos will best suit their taste.
Dealing with this data often involves running similar tasks repeatedly, and a loop gives us an easy way of managing that.
Types of loop
There are a few different types of loop in Javascript. Most looping problems can be solved with any of these, but occasionally one is better suited than the rest.
for
loop
This is a very common type of loop, used to carry out an action for a pre-determined amount of iterations. The syntax for a for loop looks like this:
for (initialExpression; condition; incrementExpression) {
statements;
statements;
statements;
}
The loop sets up with it’s initialExpression. Once done it checks the condition and if the condition is true
it executes the block of statements. Finally it runs the incrememntExpression. From here, the condition is checked again, and the loop repeats from there:
- Setup
- Check condition is true. If not, skip statements and move on.
- If true execute statements
- Execute incrementExpression
- Check condition is true. If not, skip statements and move on.
- If true execute statements
- Execute incrementExpression
- Check condition is true. If not, skip statements and move on.
- If true execute statements
- Execute incrementExpression
- Check condition is true. If not, skip statements and move on.
- If true execute statements
- Execute incrementExpression
- … etc.
For example, you may have a list of messages, and want to display the first three. You can use a for loop to append those to a page like this:
Example one
myApi.getMessages().then(function(messages) {
var i, newItem;
var n = 3;
var list = document.getElementById('totally-real-list');
if (messages.length < 3) {
n = messages.length;
}
for (i = 0; i < n; i++) {
newItem = document.createElement('li');
newItem.textContent = messages[i];
list.appendChild(newItem);
}
});
In this example we fetch some messages from a fictional API and then pass them into a function. That function sets up a few supporting variables, checks it has enough messages to display three of them and then loops through messages 0, 1 and 2 and appends them to a list.
The for loop is comprised of the four parts discussed previously:
- The initial expression: in this example
i = 0
which initialises an index (i
) as zero. - The condition: That
i
must be less thann
. (In this case, n is determined previously to be either 3, or the number of messages, if less than three.) - The incrememnt expression:
i++
which adds one to the index. - The statements: which in this example, involve creating and adding list
While
Loop
Another common loop type is the while loop. This is simpler in syntax, but can cause critical issues if not managed properly (see below). If a different loop type can be used, I would usually recommend it.
while (condition) {
statements;
statements;
statements;
}
The while loop will keep executing as long as the condition is true. This is useful, for example, in animations when you’d like to keep something moving until it hits an edge or goes offscreen etc. This change-over-time can be hard to pre-determine (as we did for our for loop) and so it suits a while loop:
Example two
function isOnScreen(element) {
var bounds = element.getBoundingClientRect();
return bounds.top > 0 && bounds.bottom < window.innerHeight;
}
var element = document.getElementById('that-element-i-want');
while (isOnScreen(element)) {
element.style.top = element.style.top - 10;
}
In this example, we keep pushing the element toward the top of the screen until it goes offscreen. Loops like this can easily fail critically though. Should the calculations behind the offscreen check be a bit buggy, or should the element fail to move when you adjust its top
position this loop will never stop running. This will crash your browser tab and give you a very bad day®.
The simple example below demonstrates the pitfalls. In this example, we fetch a numeric value from a user and use it to skim through a list step
items at a time (eg 5 or 3 or 1 items at a time). However, if the user enters a 0, or a negative numner, or anything NOT a number, i
won’t increase and the condition will never be satisfied, making the loop infinite and crashing your website.
var step = parseInt(document.getElementById('some-input').value, 10);
while (i < list.length) {
// do stuff
i += step;
}
This example would be an obvious mistake, but the concept applies to a broad range of issues. When using while loops, be sure to thoroughly check your incrementing process.
do / while
loops
Similar to while loops, and the same pitfalls apply. This loop is subtly different in that it will always execute at least once. A regular while loop checks its condition before running, so may never run at all. Do / while loops check at the end, and so always execute at least once.
do {
statements;
statements;
statements;
} while (condition)
Array methods
As well as pure loops, several array methods also loop. These include forEach
, some
, map
and reduce
amongst others. These are usually much safer alternatives to for or while loops, and should be preferred where they are available.
Escaping the loop
Sometimes a special case may cause you to need to exit a loop. When this happens you can either break
out of the loop, which will stop it there an d then, or you can continue
on to the next item in the loop. This skips the rest of the statement block for that item, but lets the loop continue.
For example you may wish to email out to all users, but skip site admins.
for (i = 0; i < n; i++) {
var user = users[i];
if (user.isAdmin) {
// Don't do this if the user is admin
continue;
}
sendEmailTo(user.emailAddress);
}
Or, you may wish to stop a test if you have too many incorrect answers
var passed = 0;
var failed = 0;
while (questions.length > 0) {
var attempt = questions.pop();
if (isCorrect(attempt)) {
passed++;
} else {
failed++;
}
if (failed > 3) {
break;
}
}
More advanced note on good practices when writing loops
Because a loop runs many times, it is good practice to only put in it that which needs to be in it. In Example one we need to get a list from the DOM, we could do this like this:
for (i = 0; i < n; i++) {
newItem = document.createElement('li');
newItem.textContent = messages[i];
document.getElementById('totally-real-list').appendChild(newItem);
}
but did not. This is because getting that element from the DOM is computationally “expensive”. We need to send the browser off to browse the DOM tree, find the correct node, grab a reference and return it to us, all of which takes time. By doing things as we did, we only need to perform that lookup once.
var list = document.getElementById('totally-real-list');
for (i = 0; i < n; i++) {
newItem = document.createElement('li');
newItem.textContent = messages[i];
list.appendChild(newItem);
}
A warning. Usually in programming pre-optimisation is frowned upon, and rightly so. Computers are so fast, and interpreters so good at optimising code, that trying to speed things up using clever tricks often just leads to ugly, unreadable code. Loops are the exception to this rule, especially loops in a webpage, where a lot of costly actions can be triggered in a line or two of code.
Especially avoid DOM manipulation and HTTP requests in loops and keep your loops lean and fast.