Just like with conditional statements, it is possible to have loops within other loops. While on the surface, this seems like an obvious and simple concept, I have noticed that it is a problem area with many of my first-year students. I highly recommend that readers play around with the concepts here until they are very comfortable with them.
The biggest concept to understand when having a loop within another loop is that the innermost loop will completely run through it’s loop for every iteration of the outermost loop. This effectively means that the inner loop is run before the outer loop, which is why a common mistake for beginners is to have the order of the loops incorrect. For example, let’s say we wanted to draw a rectangle using * characters. The incorrect way of writing this loop would look like this:
*** *** *** *** *** *** ***
So what is wrong with this? When we run it with a width of 7 and a height of 3, we don’t get a 7x3 rectangle but instead get a 3x7 rectangle. The first loop goes over the width of the rectangle, while the second loop goes over the height of the rectangle. This intuitively seems to be correct because we always describe rectangles using width x height. However, when you are printing out the rectangle you should be printing width number of asterisks. This means that you want to have the outer loop looping through the height of the rectangle while the inner loop runs through the width of the rectangle.
I will leave fixing the code as an exercise for the reader. If you are having trouble, the solution to this problem is in the NestedLoopsDemo.html file in the git repository.
Sometimes nested loops can be hidden from you. It is not that uncommon of a practice to make unwieldy code easier to read by breaking it into several functions. There is an overhead for calling a function, so breaking your code into several functions can cause your code to run slightly slower, but good compilers will often inline code or preserve necessary registers to minimize this slowdown. The key question when having an inner loop as a separate function is if this change makes the code easier to maintain and understand. If splitting a function into several functions does nothing to improve readability or maintainability but is being done simply because you don’t like large functions, then it serves no real purpose.
Sometimes, even if you would prefer to have the code all in one place, breaking an inner loop into a separate function does make sense. This is especially true if the code does something that other parts of your program may also need to do. For example, we are drawing a sequence of characters. If we are going to be doing this several times, we could simply have a function that would simply generate a string consisting of the character we want repeated several times. Our repeatChar function may look something like:
This is a very simple function, so it would not be that much work to manually write the code each time we wanted to print several of the same character, but by having it as a separate function, we can easily use it several times making our code a bit more readable. An example of where we may want to use this would be to generate more ASCII art but this time drawing a diamond. While this does not sound that much harder than the square, we now need to deal with both sequences of spaces and sequences of the character we are going to be using for the diamond. As diamonds are expensive, we will use $.
$ $$$ $$$$$ $$$$$$$ $$$$$ $$$ $
Even though this code has loops nested in other loops, this fact is hidden from us due to the use of the function call. The math in this code can be confusing, so not having the for loops in here to add further confusing helps simplify the code. Essentially, what is happening here is we are drawing a triangle by drawing two pyramids (one right-side up and one upside down). The aspect that makes this complicated is simply that we must draw diamonds with an odd size slightly different from drawing a diamond with an even size.
To deal with the problem of odd and even, we use a very simple method for determining if the size is an odd size. The nice feature of taking the mod of 2 is that you end up with 0 for even and 1 for odd, making it easy to adjust the loops based off the size. I broke the problem into two separate loops, but it could be done with a single loop by adding a bit more mathematical complexity. This would not save us any time but add complexity, so I prefer the two loops. From this information, we are able to calculate how many blank spaces and dollar signs are needed to draw that portion of the diamond.
Nesting of loops is not limited to two loops but can be as many loops as necessary. Let’s take a look at an example of a 3 dimensional loop by drawing each floor of a pyramid consecutively.
Floor 3 X Floor 2 XXX XXX XXX Floor 1 XXXXX XXXXX XXXXX XXXXX XXXXX
You will notice that I am not taking advantage of the repeatChar function as I wanted all the looping to be clear. This code could be simplified in two ways. First, you could break the function for drawing a floor out to be a separate function, and second you could take advantage of the already existing repeatChar. I will leave this refactoring work as an exercise for my readers.
We will explore nested loops a lot more in future chapters, especially when we start exploring the topic of arrays. For now we have enough knowledge of loops for our project, we just need to be able to modify the HTML page using JavaScript, which is what we will be looking at next.
A quick summary of the basics of JavaScript.
A brief look at how JavaScript was written in 10 days.
Comments. Why programmers don't write them, and how they should be written
Variables are used to store the state of a program.
Bits, Bytes, and data types.
Math on the computer similar but some symbol differences.
Various math operations can be used through the Math class.
Strings are what we call blocks of text and are used extensively.
Determining if a conditional expression is true or false
Conditional code using the if statement.
If statements can contain other if statements, this is called nesting.
Switch statements are a way of replacing large number of else if statements.
Functions let you put common code into a named function that can be called anywhere.
Loops allow you to repeat sections of code until conditions are met.
Just like conditional statements, loops can be nested but this has some special considerations.
Scripting languages give us the ability to dynamically change the web page.
Reacting to the user actions is done by handling events.
Our project for this chapter is a grid search game.
My solution to the Project.