Unravel the secrets that remain hidden from the majority of Developers
for loop. But whatever we will learn here can also be applied to other kinds of loops. The
for loop is ideal for situations in which you want to execute a group of statements a specific number of times. The nature of arrays requires that we be able to loop through or iterate on the values of that array.
The for statement simplifies loops that follow a common pattern. Most loops have a
counter variable of some kind. This variable is initialized before the loop starts and is tested before each iteration of the loop. Finally, the
counter variable is incremented or otherwise updated at the end of the loop body, just before the variable is tested again. In this kind of loop, the initialization, the test, and the update are the three crucial manipulations of a loop variable. The
for statement encodes each of these three manipulations as an expression and makes those expressions an explicit part of the loop syntax:
The codes defined inside the parentheses are vital they control the start and end of the
for loop. In total, we put three statements in the parentheses and separate them using two semicolons.
- The first statement is called the initial expression.
We use it to initialize one or more loop counters. This statement is executed at the beginning of the
forloop and is only executed once!
- The second statement controls when the
forloop should stop.
It will be executed before every loop. The
forloop will stop when the second statement returns a falsie value. The second statement must be set correctly otherwise you may get an infinite loop.
- The last statement is what we use to update each loop.
It gets executed at the end of each loop.
This is all that we learn about
for loops in most places.
While in most places they never go beyond this, in this article we will explore the unknown side of the
for loop. This will not only give you a deeper understanding of
for loop but also make you a better developer.
Are you ready? Lets us start!
The first statement can be defined outside the
The last statement can also be moved into the curly brackets
To enable a for loop to work normally. Just make sure the second statement is set correctly and the two Semicolons are capped.
Well, It wasn’t that contrasting! was it? But what if I say that we can merge the second and third statements.🙀 So, how do we do that?
First we declare a
counter and set its initial value to negative 1.
In the second statement, We compare the last element index with
counter++ we can get the last element index by subtracting 1 from the array length. There is no need to set the post-loop-expression or increment.
You may be wondering how on earth this program can work?
Here, the second statement will be tested and executed before each loop. So every time a new loop has started the value of the
counter variable will go up by 1. This is why we set
counters’ initial value to negative 1.
During the first loop, the
counter value in the curly brackets will become 1.
counter value will be bigger than the index of the last element. The comparison will return false and shut down the for loop.
Let us test it with the body statement
There is another way to merge the second and third statements.
We will use the
item variable to store an array element in the second statement.
We retrieve elements using
counter++ as the index.
So, how can this program work?
The second statement gets executed before each loop.
The code will first retrieve an array element using the
counter as the index and assign the retrieved element to the variable
item, then the value of the
counter will go up by 1.
Pay attention here value of the
counter won’t change until the array element has been retrieved and assigned. This is because the increment operator is placed behind the
counter , not before it. It means using the variable’s original value first and adding one to it later. So the
counter’s value won’t change in the current line. This is also why we set the
counter’s initial value to zero not a negative one, in the first loop
counter's value is still zero.
It won’t become 1 until the second loop the
counter value will go up by 1 with each loop eventually its value will be bigger than the index of the last element. If we retrieve an element using an index that does not exist in the array we will get
undefined, undefined is a false value, as a result, the
for statement will come to a stop inside the curly brackets.
We can directly output the item variable, we can see every element has been output.
But there is a problem with this program. All element values must be truthful. If there is a
false value, the
for loop will end immediately depending on your program design.
This feature can either save or cause you trouble!
Are you tired? Shall we go backward also?
I promise you will learn something profound about the performance of using loops in your code, which you won’t discover anywhere else!
Just have some patience, we are uncovering the secret life of loops.
First, we create a variable and we name it
counter, and set its value to array length.
Then we create a for loop. The first statement has already been set but you still need to keep the semicolon.
Any idea of how to set the second statement?
We connect the
counter to the
decrement operator and compare it with zero.
Inside the curly brackets, we retrieve the array element using counter as the index value
Let us put all the pieces together.
In the above code, the array was iterated backward every time a new loop starts.
counter value will be compared with zero and then drop by 1 with every loop. The value of the
counter will drop by 1. Eventually the
counter value will drop to zero as a result. The comparison expression will return a falsie value which will shut down the
Again wondering how on earth the above code worked?
In the above program, the key is the decrement operator!
It is placed behind the variable
counter, if the
counter value is 1 in the parenthesis then in the curly brackets its value will drop by 1 and become 0. This is why we set
counters’ initial value to array length, not array length minus 1.
Let’s try the second method.
First, we declare two variables. The first one is named
counter and we set its value to array length -1
Every element that has been output in the array was iterated backward.
The initial value of the
counter is the index of the last element. The second statement will retrieve the element using the current
counter and assign the element value to the variable
item then the value of
counter will drop by 1.
The key part is still the decrement operator being placed behind the
counter . The value of
counter will drop by 1 in the next loop. Eventually, the
counter value will become
negative 1 which is an illegal index value using an illegal index value will give us undefined, which is a false value, as a result, the
for loop will stop.
The key of the two programs is if you put the increment or decrement operator behind a variable, the variable value will not change until the next line. In the current line, the variable value stays unchanged.
Phew! That was quite long, wasn’t it?
If you still here then I have something for you!
If you have gone through all the examples carefully, then by now your brain must have grown a bit and you must be seeing the loops differently.
Loop Performance 🔥
for-in loop. Since each iteration through the loop results in a property lookup either on the instance or on a prototype, the
for-in loop has considerably more overhead per iteration and is, therefore, slower than the other loops.
Aside from the
for-in loop, all other loop types have equivalent performance characteristics such that it’s not useful to try to determine which is fastest. The choice of loop type should be based on your requirements rather than performance concerns. If loop type doesn’t contribute to loop performance, then what does?
There are just two factors:
- Work done per iteration
- Number of iterations
By decreasing either or both of these, you can positively impact the overall performance of the loop.
Decreasing the work per iteration
It stands to reason that if a single pass through a loop takes a long time to execute, then multiple passes through the loop will take even longer. Limiting the number of expensive operations done in the loop body is a good way to speed up the entire loop.
The above examples do a property lookup for
arr.length every time through the loop. Doing so is wasteful, as this value won’t change during the execution of the loop and is therefore an unnecessary performance hit. You can improve the loop performance easily by doing the property lookup once, storing the value in a local variable, and then using that variable in the control condition:
You can also increase the performance of loops by reversing their order. Frequently, the order in which array items are processed is irrelevant to the task, and so starting at the last item and processing toward the first item is an acceptable alternative. Reversing loop order is a common performance optimization in programming languages but generally isn’t very well understood.
Both were kept in mind when we altered the usual way of writing a
for loop in the initial examples. So, if you paid attention to those examples, then Congratulations! You can now write performant loops.
Decreasing the number of iterations
When iterated thousands of times, even the fastest code in a loop body will add up. Additionally, there is a small amount of performance overhead associated with executing a loop body, which just adds to the overall execution time. One can lead to greater performance gains by decreasing the number of iterations throughout the loop. The most well-known approach to limiting loop iterations is a pattern called Duff’s Device.
The basic idea behind this Duff’s Device implementation is that each trip through the loop is allowed a maximum of eight calls to
doSomething(). The number of iterations through the loop is determined by dividing the total number of items by eight. Because of Algorithms and Flow Control, not all numbers are evenly divisible by eight, the
startAt variable holds the remainder and indicates how many calls to
doSomething() will occur in the first trip through the loop. If there were 12 items, then the first trip through the loop would call process() 4 times, and then the second trip would call process() 8 times, for a total of two trips through the loop instead of 12.
Whether or not it’s worthwhile to use Duff’s Device, depends largely on the number of iterations you’re already doing. In cases where the loop iterations are less than 1,000, you’re likely to see only an insignificant amount of performance improvement over using a regular loop construct. As the number of iterations increases past 1,000, however, the efficacy of Duff’s Device increases significantly. At 500,000 iterations, for instance, the execution time is up to 70% less than a regular loop.
A summary of what we have learned
- The first statement(initialize) can be defined outside the for loop.
- The last statement(increment) can also be moved into the curly brackets
- We can merge the second and third statements
- If there is a
falsevalue in the test, the
forloop, it will end immediately.
for-inloop is slowest of all due to property lookup.
- Work done per iteration and Number of iterations determines the performance of any loop.
- Using Duff’s Device in larger iterations, the execution time is up to 70% less than a regular loop
We are not finished yet!
If you want to solidify what you learned here, then open repl.it, and try out the codes shown in the article. Measure the performance, and tell me in the comments which one you found the most performant.
Liked the post? I would appreciate it if you share it with your friends! Want some more insightful articles? Well, then catch me on Twitter! 🐥