JavaScript while
Loop
Learning outcomes:
- What is the
while
loop meant for - Syntax of
while
- Basic
while
examples - The
do...while
loop - Nested loops
Introduction
As we learnt in the previous chapter on the for
loop, there are essentially two main categories of loops in JavaScript — for
and while
. We've already covered for
quite extensively, and likewise what's left now is while
.
In this chapter, we aim to unravel the purpose behind while
in addition to considering an array of various examples of its usage. Without any single doubt, while
forms a crucial part of modern-day programming. Many many algorithms are powered by the powerful nature of while
.
So what is while
? Let's see it...
What is while
meant for?
By design:
while
loop is meant to repeatedly execute a piece of code an unknown number of times.For instance, if we want to print 'Hello'
until the user enters -1
in an input prompt, what we need is the while
loop.
Similarly, if we want to iterate over a queue, removing items one-by-one, until there is no item left, this could also be done using a while
loop.
Technically speaking, anything that can be done, or is done, using while
can also be done using for
, and vice versa. It's just that the syntax of while
sometimes suits the situation better and obviously asks for less setup than a for
loop.
Let's now see the syntax of while
.
Syntax of while
The while
loop begins with the while
keyword, followed by a pair of parentheses (()
) encapsulating the iteration condition, followed by the loop's body.
Here's a view of this syntax:
while (condition) statement;
The loop continues iterating as long as the given condition
remains truthy. The moment it becomes false
, the loop ends.
If you recall, this is identical to how the condition in a for
loop works — that is, if it's true, the next iteration happens, or else the loop ends.
With the syntax also done, it's finally time to consider some quick examples.
Examples of while
Summing some positive numbers
Suppose we want to compute the sum a couple of positive numbers entered by the user.
The way the entry happens is via an input prompt for the first number, followed by another input prompt for the second number, and so on, until the value entered is -1
. -1
signals the end of the whole stream of numbers to add.
Such a special value is often referred to as a sentinel. A loop that iterates up until the point a sentinel is seen is, likewise, referred to as a sentinel-controlled loop.
In our case, -1
works as a sentinel because we want to add positive numbers only; -1
being a negative number is a good candidate for signalling the end of our inputs.
Anyways, this task can very easily be accomplished with the help of while
as shown below:
var sum = 0;
var input = prompt('Enter a number, -1 to exit.');
while (input !== '-1') {
sum += Number(input);
input = prompt('Enter a number, -1 to exit.');
}
alert(`The sum is ${sum}.`);
If we were to accomplish the same thing using for
, we'd go like:
var input = prompt('Enter a number, -1 to exit.');
for (var sum = 0; input !== '-1'; ) {
sum += Number(input);
input = prompt('Enter a number, -1 to exit.');
}
alert(`The sum is ${sum}.`);
See how the syntax of for
is a little bit less intuitive and a little more to type. For example, the third part of the loop's header, i.e. the update expression, is omitted, and rightly so — we don't need it.
Clearly, while
is the better choice in this case.
for
is better suited to iterate a known number of times, for e.g. iterating over a string, over an array, an n number of times, and so on.Removing array elements
As another example, suppose we want to remove elements from the end of an array, using the pop()
method, until it becomes empty. This also can be done nicely using a while
loop.
Consider the following code:
var arr = [1, 3, 5];
while (arr.length !== 0) {
console.log(arr.pop());
}
The condition arr.length !== 0
checks if the array has anything remaining in it. If there is something remaining, the condition evaluates to true
, and hence the loop's body executes, thereby removing the last element from the array (via the arr.pop()
call).
Note that arr.pop()
effectively reduces the length of arr
as the loop progresses and thus takes it closer and closer to the success of the condition arr.length !== 0
. Without arr.pop()
, we'd get an infinite loop.
Although the code above works perfectly, you'll often see one common convention used out there to check whether an array has elements remaining within it.
That is, for a given array arr
, instead of using arr.length !== 0
to check whether there are any remaining elements in arr
, the expression arr.length
is used.
When it coerces to true
, it simply means that the array's length is not 0
and hence there is still something remaining in it. This is effectively identical to arr.length !== 0
.
Likewise, the code above can be rewritten as follows:
var arr = [1, 3, 5];
while (arr.length) {
console.log(arr.pop());
}
The while
loop here can be read as follows: "While the array has some length, remove its last element."
The do...while
loop
One often-overlooked variation of the while
loop, with a sligtly different syntax, is the do...while
loop. It serves a crucial purpose that the typical while
doesn't.
do...while
first evaluates the loop's body and then checks the condition (for the next iteration).Hence, when the given condition is false to begin with, do...while
still executes the body once unlike a normal while
loop.
First, let's see the syntax of do...while
:
dostatement;
while (condition);
As before, statement
is the loop's body whereas condition
is the iteration condition.
;
) at the end of the do
statement. That's because after the first semicolon (which is optional), the do
statement ends, and likewise a while
is expected before the second semicolon. Putting two semicolons one after another simply misses out the while
statement, and this is the reason why doing so is syntactically invalid.Now you might ask what's the benefit of this approach?
Well, sometimes we do want to execute a certain piece of code and only after that check for some condition, before executing the code again.
A common example would be obtaining an input again and again till the entered value is valid.
Consider the following code:
do {
var input = prompt('Enter a number');
}
while (isNaN(Number(input)));
alert(`You entered the number ${input}`);
First we have the do
block with one statement, asking for the user's input which must be a valid number. Next, in the while
part of the loop, we check whether the value input coerces to NaN
. If it does, this means that the provided input was some arbitrary value not able to be coerced into a number, and so likewise we must repeat the prompt.
In words, we can read the code above as "keep asking for the user's input while the entered value is NaN
."
Such a loop that runs until an entered value is valid is often referred to as an input-validation loop.
Note that the code above can be rewritten using a plain while
loop as well. Below shown is an illustration:
var input = prompt('Enter a number');
while (isNaN(Number(input))) {
input = prompt('Enter a number');
}
alert(`You entered the number ${input}`);
Notice that we have to repeat the loop's body before the actual while
statement. This is so that input
can be set to a particular value before executing the loop, asking the user to input again.
One obvious way out of this repetition is to predefine the variable input
with a dummy value (undefined
will also work in this case) that'll get at least the first iteration of the loop to execute.
For instance, we can set input
to NaN
ourself, and thus get the loop's condition to be met, thereby leading to the execution of the input prompt, after which input
will be evaluated once again for the next iteration.
// Set to NaN in order to execute the following loop at least once.
var input = NaN;
while (isNaN(Number(input))) {
input = prompt('Enter a number');
}
alert(`You entered the number ${input}`);
This technique surely works, but it's not really that intuitive.
Ideally, we should use do...while
for such a scenario since it was made purposefully for such a scenario. Moreover, with this approach, we have to predeclare the variables involved in the loop's condition before the while
statement.
This doesn't have to be done with a do...while
loop — the respective variables can be defined right inside the do
block and then remain accessible in the while
clause.
To boil it down, whenever we wish to execute a piece of code repeatedly but check the condition after the code (not before it), we must use a do...while
loop. It might be an occasional programming construct but when used, is extremely versatile and elegant.
Nested loops
What's more interesting in a program than a set of nested loops. And if those loops all belong to the while
family, things become yet more interesting.
So what do you say? Shall we consider a complicated example of nested loops?
Let's suppose we want to ask the user to input a list of numbers.
Each number is entered in a separate input prompt. If the entered value is not a number, an error message is output followed by asking the user to input again. This goes on until the sentinel value -1
is entered, marking the the end of the whole list.
Here's the code that does this using two do...while
loops:
var sum = 0;
do {
// Obtain the correct input
do {
var inputNumber = Number(prompt('Enter a number, -1 to end.'));
if (isNaN(inputNumber)) {
alert('Entered value is invalid.');
}
}
while (isNaN(inputNumber));
// Add the input
if (inputNumber !== -1) {
sum += inputNumber;
}
}
while (inputNumber !== -1);
alert(`The sum is ${sum}.`);
The outer loop is a sentinel-controlled loop that iterates until the point the value -1
is input. With each iteration of this outer loop, the entered value is added to the previous sum stored in sum
, but only if the entered number is not -1
.
Contrary to this, the inner loop is an input-validation loop that iterates until the point the value entered is valid. Once the input is valid, the inner loop ends and likewise provides the correct value of inputNumber
to the following code, i.e. line 12 where the addition takes place.
Note that the task above can also be accomplished using continue
in lieu of a set of nested loops. Here's one way to rewrite the code above:
var sum = 0;
do {
var inputNumber = Number(prompt('Enter a number, -1 to end.'));
if (isNaN(inputNumber)) {
alert('Entered value is invalid.');
continue;
}
if (inputNumber !== -1) {
sum += inputNumber;
}
}
while (inputNumber !== -1);
alert(`The sum is ${sum}.`);
The inner loop is gone and in place of that we have a simple condition to check if the input number is NaN
. If it really is NaN
, the error message is shown (as before) followed by the continue
statement.
Recall that continue
effectively skips any code that comes after it and continues execution with the next iteration.
In the code above, when continue
is encountered, the entire logic in lines 11 - 13 is ignored and execution tips back to the beginning the loop (obviously after checking the condition), thus making the desired input prompt again.
Although this code does the same job as the previous one, you may agree that it's slightly less readable.
As we stated before, continue
and break
tend to introduce holes into the reading flow of a program — we can't really be sure whether any following code will be executed until and unless we go through the entire loop containing these control-flow commands. Without them, the code speaks of itself.
Let's review the same code above that contained a set of nested loops and see how exactly is it more readable than the one with continue
:
var sum = 0;
do {
// Obtain the correct input.
do {
var inputNumber = Number(prompt('Enter a number, -1 to end.'));
if (isNaN(inputNumber)) {
alert('Entered value is invalid.');
}
}
while (isNaN(inputNumber));
// Add the input, if not -1.
if (inputNumber !== -1) {
sum += inputNumber;
}
}
while (inputNumber !== -1);
alert(`The sum is ${sum}.`);
The outer loop is the same as before so there is really nothing special to consider in it.
The inner loop is the main point. It is tasked with obtaining the correct input and then giving us back the respective inputNumber
. That is, by line 12, we are sure that inputNumber
is valid. Moreover, with this inner loop instead of continue
, there aren't any holes while reading the given program.
All in all, whenever possible, resort to using basic programming constructs to achieve a given task, rather than using the control-flow commands continue
and break
.
Spread the word
Think that the content was awesome? Share it with your friends!
Join the community
Can't understand something related to the content? Get help from the community.