Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

JavaScript for Loop

Chapter 25 26 mins

Learning outcomes:

  1. Introduction to loops
  2. What is the for loop meant for
  3. Syntax of for
  4. Basic for loop examples
  5. Nested for loops
  6. The break and continue keywords
  7. The return keyword

Introduction

Loops, also known as loop statements or iteration statements, are amongst those ideas in programming without which it's not just difficult but totally impossible to imagine this modern era of computing. Computers are the heart of automation and loops are the forerunner in enabling that.

Essentially a loop is merely a block of code together with some set of instructions on how long to keep that code running again and again. Back in the day when programming languages were invented, we didn't have the loops that we have today.

Over time as programming matured, people realized the need of such a neat programming construct that could fit in well with our intuitive reasoning of repetition. And thus came in the idea of loops as we use them today.

The two most conventional looping statements provided by almost all mainstream languages are for and while. Each has its own specific purpose but the idea is the same — keep repeating code until some condition becomes false.

In this chapter, we start off by exploring all the nitty gritty details of the for loop, followed by those of while in the next chapter.

Let's begin.

What is for meant for?

So what is for meant for?

Well, precisely speaking:

The for loop is meant to repeatedly execute a piece of code a known number of times.

For instance, if we want to print 'Hello' a thousand times, or process as many <a> elements in the HTML document as given by the variable anchorsLength, then what we need is the for loop.

In both of these cases, we know the limit to the iteration in one way or the other.

Compare this with, let's say, repeatedly asking the user to input a number (using a prompt() dialog) until the input is -1. Here clearly we don't know how many times would the code repeat before execution jumps out of it, hence this is not a situation meant for for (however, technically, it could be used here as well — we'll shortly see how).

To restate it, for is used to iterate a known number of times.

This is the reason why it's common to use for to iterate over arrays using their length property or, in general, any other sequence.

Anyways, with the purpose of for understood, it's time to see how to write a basic for loop.

Syntax of for

The for statement begins with the for keyword, followed by a set of configurations enclosed in a pair of parentheses (()), known as the loop's header, followed by the statement to repeatedly execute, known as the loop's body.

Here's the syntax:

for (initialization; condition; update)
   statement;

The pair of parentheses following the for keyword consists of three different configurations, each separated by a semicolon (;).

  1. initialization — here any variables to be used in the loop are initialized to given values. Moreover, even variables can be declared, for example using var.
  2. condition — the condition that's evaluated before every iteration. If it evaluates to true, the loop's body is executed, or else execution moves out of the loop.
  3. update — an expression that's evaluated after every iteration. Typically this updates a variable's value that's used in the loop's condition so that it eventually becomes false at a certain point, and thus the loop comes to an end.

Note that only expressions are allowed in each of these three sections. The only exception to this rule is in the first section where variable declarations can also be done.

Remember that a variable declaration is not an expression.

Moreover, it's invalid to include more or less than two semicolons in the for loop's header. The individual expressions can be omitted but the semicolons have to be there. We'll see numerous examples of for loops shortly below.

Now, if we were to go with all this description of the syntax of for, we'd arrive at the following syntax.

for ([initialization]; [condition]; [update])
   statement;

Notice the [ ] around each of the three configuration expressions — they signify the fact that all the three expressions are optional.

Simple examples

In this section, we aim to see a couple of examples of the usage of for. With each example, we cover a lot of aspects of how to rewrite the for loop.

Basic counting

Consider the problem of logging 0 to 4 using a for loop.

This could very easily be done as follows:

for (var i = 0; i < 5; i++) {
   console.log(i);
}
0 1 2 3 4

Let's understand how this loop works:

  1. First, in the statement var i = 0, we declare a new variable i and initialize it to 0. This variable will keep track of the iteration we are currently on, and obviously also be used in the output. Such a variable that's meant to drive a given loop is often known as a loop variable, or even as a loop counter.
  2. Secondly, the condition i < 5 means that i should be less than 5 for the given body to be executed.
  3. Lastly, the update expression i++ means that after every iteration, i is incremented by 1.

Hence, when i = 0 (initially), the loop executes; when i = 1, the loop executes; when i = 2 the loop executes; this goes on until i becomes equal to 5 at which point the evaluation of i < 5 yields false and consequently the loop ends.

Simple, isn't this?

Note that the same output could've also been obtained by slightly modifying the condition. That is, instead of using i < 5, we could've also used i <= 4. This is because the condition i <= 4 (akin to i < 5) yields true for all the values 0, 1, 2, 3 and 4.

Here's an illustration of this fact:

for (var i = 0; i <= 4; i++) {
   console.log(i);
}
0 1 2 3 4

Moving on, it's also not necessary to declare the variable in the loop's header — it could be declared before as well.

For example, the same code above could be expressed as follows:

var i;
for (i = 0; i <= 4; i++) {
   console.log(i);
}

Here, i is declared in line 1 separately. Inside the for loop's header in line 2, it's only assigned the value 0 to begin with.

The inline declaration of a loop variable inside the loop's header, as we did above, simply keeps the code compact and in certain cases (such as when we use let) also affects the scope of the variable. Whenever possible, it's recommended to follow this convention.

Iterating over an array

One of the most common uses of for is to iterate over an array, or any other sequence such as a string, or an HTML element collection (as we shall see in the HTML DOM unit).

The main thing used in this case is the length of the sequence (i.e. the total number of elements in it). For arrays, we already know that the length is given by the length property.

Likewise, what we do is start at the index 0 and go as long as the index remains less than the length of the sequence. That's because the last element's index is one less than the length of the sequence, and therefore we don't have to end right at that very point.

In the code below, we have an array of numbers.

var nums = [1, 10, 5, -9, -1];

What we want to do is to log each number separately. That's accomplished as follows:

var nums = [1, 10, 5, -9, -1];

for (var i = 0; i < nums.length; i++) {
   console.log(nums[i]);
}
1 10 5 -9 -1

Once again, the loop's counter i begins at 0 and goes right upto nums.length (obviously excluding it), with being incremented after each iteration. Inside the loop's body, the ith element of nums is logged using nums[i].

Simply amazing!

If we want to, we can add a bit of spice in the code above. Instead of merely logging the current item of the array, we can also label it, and thus specify which index does the item have.

Consider the code below:

var nums = [1, 10, 5, -9, -1];

for (var i = 0; i < nums.length; i++) {
   console.log('nums[' + i + ']: ' + nums[i]);
}
nums[0]: 1 nums[1]: 10 nums[2]: 5 nums[3]: -9 nums[4]: -1

As can be seen, this time the logs are a bit more detailed, covering the index of each logged item.

Alright, it's now time for one very quick and easy task...

Given the same nums array as shown above, write some code to log its elements in reverse-order using a for loop.

The expected output is the following:

-1 -9 5 10 1

To go in reverse order, we ought to begin at the very last index, proceed backwards, and continue as long as the index remains greater than or equal to 0.

Hence, we get to the following code:

var nums = [1, 10, 5, -9, -1];

for (var i = nums.length - 1; i >= 0; i--) {
   console.log(nums[i]);
}

Moving on, one common thing you'll notice across code snippets is the following:

var nums = [1, 10, 5, -9, -1];

for (var i = 0, len = nums.length; i < len; i++) {
   console.log('nums[' + i + ']: ' + nums[i]);
}

Can you spot the difference? Well, it's the expression len = nums.length and then the condition's modification to i < len from i < nums.length.

So what's so special about this change?

Recall that the loop's condition, i.e. the second expression after the semicolon (;), is evaluated before every iteration. When the condition is i < nums.length, the length property is retrieved again and again and again in this evaluation.

The cost of this expression gets further increased if it is tied to an HTML element collection, in which case the whole computation of the collection is done again on the document's DOM tree. We'll see the details to this in the HTML DOM — Accessing Elements chapter.

To prevent this overhead of a property access (which, as stated before, might trigger an internal function call), programmers typically cache the value of the property in a variable and then refer to that variable.

Getting numbers input

Suppose we want to input some numbers to be added together. How many numbers we want to add is specified in an initial prompt dialog. Thereafter, as many additional prompts are made asking for each of the numbers to be added.

This is accomplished as follows:

var n = Number(prompt('How many numbers?'));

var sum = 0;
for (var i = 0; i < n; i++) {
   sum += Number(prompt('Enter number ' + (i + 1)));
}

document.write(sum);

Live Example

Notice a couple of things here:

Firstly, the variable sum is declared outside the loop, whereas i is declared inside the loop's header. This can be a bit confusing for a newbie programmer as to where exactly to declare different variables. Fortunately, the key is very simple.

sum is a variable meant to be used later on in the program, particularly when outputting the sum of the numbers. It's surely used in the for loop, but it doesn't necessarily dictate the execution of the loop. In contrast, i is the loop's counter which isn't meant to be used after the loop is done executing — it's purely limited to the loop.

Henceforth, this means that we should declare any variable that's meant to govern the execution of a loop inside the loop's header, and any other variable outside the loop.

Moreover, we begin at i = 0 even though we could've begun at i = 1 and changed i < n to i <= n. The thing is that it's very conventional and natural to begin at 0 and iterate the given number of times using the < operator, even though sometimes the 0 might not have any practical significance as in the code above.

Note that if the expression (i + 1) was repeatedly needed in the loop's body above, then we might've considered changing i = 0 to i = 1 and the conditional expression i < n to i <= n consequently as well to ultimately replace (i + 1) with i. However, the expression (i + 1) was used only once and likewise we didn't consider modifying the loop's header.

Nested loops

A for loop's body is a piece of code just like any other piece of code in a program. This means that it could contain another for loop as well.

We usually refer to this as a nested loop. The inner loop is said to be nested inside the outer loop.

Nested loops are extremely common in programming. The majority of algorithms and data structures that you'll implement in your programming career will require you to employ nested loops. So let's quickly see how to set up a nested for loop.

First let's come up with a scenario. Suppose we have to print ordered pairs of the form (i, j) where i is 0, 1, 2 and j is 0, 1, 2.

The way we'd do so is to first set i = 0 in the outerloop and then iterate with j set to 0, 1 and 2; then increment i and repeat the iteration over j; then increment i again and repeat the iteration over j.

Consider the following code:

for (var i = 0; i < 3; i++) {
   for (var j = 0; j < 3; j++) {
      console.log(`(${i}, ${j})`);
   }
}
(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)

It's very intuitive to follow along. For each iteration of the outer loop, the inner loop iterates three times.

Conventional naming: i, j and k

Note that using i and j as the loop counter variables in a nested loop is a convention. In fact, when there are a total of three loops, the variables used are i, j and k in that order, starting with the outermost loop.

Perhaps this has been influenced from the theory of vectors and matrices in mathematics, where the same names are used to denote given variables.

Whenever designing nested loops in this course, we'll follow this convention unless there is a valid reason to use some other naming.

Time to test you understanding of nested loops.

Write some code to achieve the following output:

(0, 0) (1, 0) (2, 0) (0, 1) (1, 1) (2, 1) (0, 2) (1, 2) (2, 2)

Before writing the code, we have to focus on the output and see which element in the ordered pairs is changing quicker than the other one. That's clearly the first element.

Hence, this hints us that the inner loop (with j as its counter variable) will produce this first element of the ordered pair. The second element will be produced by the outer loop (with i as its counter variable).

Here's one way to accomplish this task, and the preferrable way:

for (var i = 0; i < 3; i++) {
   for (var j = 0; j < 3; j++) {
      console.log(`(${j}, ${i})`);
   }
}

Another way could simply be to swap the variable names i and j:

for (var j = 0; j < 3; j++) {
   for (var i = 0; i < 3; i++) {
      console.log(`(${i}, ${j})`);
   }
}

This isn't preferred since the variable j comes first in the outer loop followed by i in the inner loop — ideally it should be the case that i comes first and then j.

The break and continue keywords

JavaScript, like almost all mainstream languages, provides two common control flow commands that dictate the execution of a loop — break and continue.

break

As the name suggests,

break serves to break execution out of the loop that it is placed within

It's more or less like a shortcut to terminate a given loop. Anything following the break command isn't executed in the loop — execution immediately jumps out.

Let's see a quick example.

In the code below, we have a basic loop, counting from 0 to 5. The if conditional inside the loop checks for i === 2. The moment that happens, execution jumps out of the loop:

for (var i = 0; i < 5; i++) {
   if (i === 2) {
      break;
   }

   console.log(i);
}

Here's the output produced by this code:

0 1

As is evident, the console.log(i) statement executes just twice. In the third iteration, when i === 2 is true, this leads to break executing (on line 3). Consequently, the console.log(i) statement (on line 5) gets ignored.

Let's try to modify the position where break is called:

for (var i = 0; i < 5; i++) {
   console.log(i);

   if (i === 2) {
      break;
   }
}

Here's the output produced by this code:

0 1 2

This time, since console.log(i) is before the break command, it executes for the third iteration as well (when i = 2) unlike previously, and hence we get the third log.

break only breaks execution out of the loop where it is used — it won't break execution out of the parent loop (if there's any).

break is undoubtedly a useful command, but use it very carefully. It does reduce the readability of code. Whenever possible, try to avoid using break in place of a simple and intuitive conditional expression in the header of the loop.

Let's see an instance of what does it actually mean for break to reduce the readability of code.

Consider the following code:

var nums = [1, 11, 3, 2, 5];

for (var i = 0; i < nums.length; i++) {
   if (nums[i] % 2 === 0) {
      break;
   }

   console.log(nums[i]);
}
1 11 3

The loop's header clearly shows that we want to iterate over the entire array. However, inside the loop, the additional if conditional checks whether the current element is an even number. If it is, the loops exits.

In other words, we want to process the elements of the array until an even number is encountered.

As you may agree, this isn't immediately evident just by reading the loop's header. Ideally, we should try to be as informative in laying out the loop's condition as we can to make sure that anyone reading the code can pick up the purpose of the loop right away.

A much better approach would be to join both the given conditions together, as done below:

var nums = [1, 11, 3, 2, 5];

for (var i = 0; i < nums.length && nums[i] % 2 !== 0; i++) {
   console.log(nums[i]);
}

The loop's condition simply means that the execution of the loop should continue if i is less than nums.length (i.e. we don't exceed the last element of the array) and if nums[i] is not an even number (i.e. we don't want to process an even number).

See how break has been removed from our code, yet the loop still works as it did before.

The point of this example is to emphasize on the fact that break should be used sparingly in loops. This isn't because it degrades performance — it doesn't affect the performance of the script in any way. It's only because it costs the fluid readability of the given code.

That's it.

continue

Let's now move to continue.

The continue keyword serves to signal to the JavaScript to the engine to skip the current iteration and move to the next one.

Effectively this means that any code following the command isn't executed, and execution moves to the next iteration if there is any remaining. If no iteration is remaining, then obviously the loop terminates.

Let's consider a quick example.

In the code below, we iterate over the given array nums and skip the loop's body if the current element is an even number.

var nums = [1, 11, 3, 2, 5];

for (var i = 0; i < nums.length; i++) {
   if (nums[i] % 2 === 0) {
      continue;
   }

   console.log(nums[i]);
}
1 11 3 5

Clearly, this code could be improved by removing the call to continue and instead using an if conditional to check if a log ought to be made (i.e. the current number is odd).

This is accomplished as follows:

var nums = [1, 11, 3, 2, 5];

for (var i = 0; i < nums.length; i++) {
   if (nums[i] % 2 !== 0) {
      console.log(nums[i]);
   }
}
1 11 3 5

Without any doubt, this second code snippet is much more readable than the previous one that employed continue.

Long story short: continue, as with break, is a very useful command to control the execution of a given loop. However, we should make sure to use it sparingly as well, just like break, and rather try to use if...else conditionals in a way that gets the same job done but in a more readable manner.

With this done, it's time to see the return keyword as used inside a loop.

The return keyword

As we saw in the chapter JavaScript Functions, the return keyword is used inside a function to immediately terminate execution and return a given value to the calling context.

We also know that it's invalid to use return outside a function. Therefore, if we want to use return inside a loop, the loop has to be part of a function's body.

Using return in a loop, which is obviously itself a part of function, is a very common idea. Why?

Simply because it does two things:

  1. It breaks execution out of the function which effectively means that no matter how many loops are nested together, return would exit them all and the containing function as well.
  2. It returns a value to the calling context i.e. the place where the function was called.

One quick example could be a function that searches for a given number in a matrix (represented as an array of arrays).

The search would use a double nested loop and inside the inner loop a mere conditional to check for the number. If it finds the number we were searching for, true is immediately returned before bringing the entire execution of the function to a halt.

Following is this example brought to the glyphs of code:

var matrix = [
   [0, 5, 6],
   [1, 2, 10],
   [0, 0, -1],
];

function searchMatrix(matrix, value) {
   for (var i = 0, n = matrix.length; i < n; i++) {
      for (var j = 0; j < n; j++) {
         if (matrix[i][j] === value) {
            return true;
         }
      }
   }
   return false;
}

console.log(searchMatrix(matrix, 10));
console.log(searchMatrix(matrix, 2));
console.log(searchMatrix(matrix, -50));
true true false

And this is it.