DEV Community

Cover image for So You Think You Know For Loops?
Travis Bennett
Travis Bennett

Posted on

So You Think You Know For Loops?

So you've been learning JavaScript for a while; perhaps you've written several programs and solved dozens of problems on Code Wars? Or maybe you're just working your way through some tutorials and courses, or even just starting to get your feet a little wet? I assure you, if you've been writing all of your for loops like this:

for (let i = 0; i < n; i++) {
}

you're only scratching the surface of the for loops potential.

During my coding journey, I have discovered the weight room to have the greatest philosophical carryover to programming. Nobody in the weight room would believe they have a complete bench by exclusively doing flat barbell bench. In the weight room, you learn to hit the muscle from different angles and develop strength across several different planes of motion. Then yet, in programming, so many tutorials and resources only teach from a one dimensional perspective, the programming equivalent of exclusively doing flat barbell bench. Is it any wonder people get stuck in tutorial hell, when the tutorials do not approach learning from different angles and perspectives? That's why I think it's important to approach the for loop from an entirely different angle, to develop perspective on its true potential, and to develop a deeper understanding of how JavaScript works.

I took inspiration for this post from the Chapter 5 of the book Eloquent JavaScript, by Marijin Haverbeke. It helped me see for loops in an entirely different perspective, one that I have yet to see in any single JavaScript tutorial or course yet. And I'm going to break it down in greater detail than the book itself. So grab your favourite beverage and hang on tight, this one's going to take you for a loop!

The for loop in this example takes a starting value, a test function (conditional expression) that if true, calls the body function and passes the current iterated value (the value of i) to the body function, which subsequently calls the update function with the value of i, updating the loop value. In text alone, this sounds quite convoluted and confusing, so let's take a look at the code.

`const loop = (value, testFunction, updateFunction, bodyFunction) => {
for (let i = value; testFunction(i); i =updateFunction(i)){
bodyFunction(i)
}
}

loop(3, n => n > 0; n => n - 1, console.log)
`
To understand what is going on here, we need to take a look at the arguments being passed into the loop function. The value being passed in is 3, n => n > 0 = testFunction, n - 1 = updateFunction, and console.log = bodyFunction. This would commonly be written out as:

`for (let i = 3; i > 0; i--) {
console.log(i)

}`

But if it was written out like this, it would miss out on the power of JavaScript: you can pass values directly as arguments to a function call without having to declare them first as variables! This allows for more refined and customized control of the loop via callback functions! While in most use cases, using a traditionally instantiated iterator (let i = insert value) would be the best case, there may be use cases where one would want to control the loops behaviour via callback functions. By passing in values directly as function calls, it allows to write code more adherent to DRY principles, and thereby eliminates repetition if the values had to be declared elsewhere with let or const. Furthermore, this example demonstrates the power and flexibility of Javascript that is never shown in tutorials or courses when teaching loops. To write good code adherent to functional programming standards, understanding how functions and values can be passed as arguments is key, especially when chaining together several higher order functions, which is a common practice in the React framework.

So take a moment and experiment with the code example, change the values, and dig deeper to develop a greater understanding of the for loop. I encourage you to try and solve other problems by writing for loops in this manner, it will pay dividends later in your coding journey when you write more callback functions to solve problems.

Top comments (25)

Collapse
 
blindfish3 profile image
Ben Calder • Edited

I haven't made much use of for loops in years (array methods like forEach, map and reduce are much nicer to work with), so I was curious what you were going to come up with. It's interesting, but I'm wondering whether the same could be achieved easily enough with a recursive function. What advantages do you think a for loop brings here?

Collapse
 
ravavyr profile image
Ravavyr

The main advantage is speed. A standard "For" loop is always faster. All the other ones like "forEach" are shown to be slower.
Of course, for the vast majority of situations this is negligible.
I just use For loops because I've run into enough situations where it mattered and it takes no extra effort using a standard for loop versus any other loop, plus it makes all my code consistent.

Collapse
 
blindfish3 profile image
Ben Calder • Edited

Sure, I know about the possible performance boost of a for loop compared to array functions; but my question was about comparing a for loop used in this way and a recursive function.
Both achieve the same result but IMO a recursive function is easier to follow in terms of the code:

function recursiveLoop(value, condition, update, output) {
  if (condition(value)) {
    output(value);
    recursiveLoop(update(value), condition, update, output);
  }
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
koga73 profile image
AJ

Recursive functions are often harder to read and debug and suspectable to stack overflows depending on the recursion depth. Besides that for loops have another advantage over the array functions - you can use async / await. If you need to await something each iteration a for loop works fine but using forEach doesn't

Thread Thread
 
blindfish3 profile image
Ben Calder

So you're saying the OP's for loop is more readable and easier to debug than my suggested recursive function? Here's the loop approach with some formatting applied:

const loop = (value, testFunction, updateFunction, bodyFunction) => {
    for (let i = value; testFunction(i); i = updateFunction(i)){
        bodyFunction(i)
    }
}
Enter fullscreen mode Exit fullscreen mode

And you too have misinterpreted my comment: I wasn't asking why the OP's for loop was a better option than array methods. I was asking what made his convoluted use of a for loop a better approach than a recursive function.

Thread Thread
 
ravavyr profile image
Ravavyr

It's that For Loops are far better performance-wise than recursive functions.
And visually, to me anyway, for loops have always been easier to read than recursive functions since the "duplicate" name appearing within itself can be confusing.

To quote baeldung.com
"We can say that if we keep all other factors the same, recursion is slower than looping. This is so because recursion adds function calling overhead to its execution. And that makes it slower than iteration."

also

"Recursion uses a function call stack to store the set of new local variables and parameters on each function call. On the other side of the spectrum, we have looping that doesn’t use any stack. Hence, recursion incurs more memory cost since they add the overhead of stacking/unstacking operation. Moreover, we find that recursion often leads to stack overflow problems for larger input."

It's all in part 4 on this page: baeldung.com/cs/recursion-looping

Collapse
 
chasm profile image
Charles F. Munat

Hey, Travis!

Three backticks followed by the syntax (js) then the code block and finishing with three more backticks.

This Markdown implementation is utterly broken, so I cannot show you what I mean, but you can figure it out.

Collapse
 
chasm profile image
Charles F. Munat

P.S. Your loop function is the dumbest thing I've seen in a long time. Instead of making the already ugly loop less complex, it complicates it further and hides the inner workings.

I suggest you learn a bit about FP and check out the (admittedly methods) map, find, filter, reduce, forEach, etc. methods already available in JS. Furthermore, the basic for loop you use is the oldest and ugliest of the available for loops. If you must use a for loop. try for-in and for-of.

Collapse
 
jjgmckenzie profile image
James McKenzie

When I clicked the article in my recommendeds I presumed it would be about FP methods available in JS, rather than that loop.

Thread Thread
 
chasm profile image
Charles F. Munat

Me, too.

Collapse
 
virtualmachine profile image
ByteCodeProcessor

looks like they were trying to do some rust like implementation here

Thread Thread
 
chasm profile image
Charles F. Munat

I've noticed that often when people come from one language to another and they don't find exactly the same tools that they're used to, then they assume that the language is "broken" and they try to "fix it" by reproducing the tools with which they are familiar, instead of simply embracing the new language.

I'm not saying that that is what happened here – I don't know – but I've seen it a lot (and as a teacher, I find teaching those who already know a language is always harder than teaching newbies because they are always trying to force the new knowledge to fit with the old).

Whatever the reason, the loop function is a terrible idea. Added complexity for no gain at all.

Thread Thread
 
blindfish3 profile image
Ben Calder

You're a teacher and you're comfortable posting really negatively phrased feedback on a public forum? I think that's

the dumbest thing I've seen in a long time

Thread Thread
 
chasm profile image
Charles F. Munat

Yep. Quite comfortable.

The author begins with the boast "So you think you know for loops?" Then proceeds from his soapbox to promote – confidently – utter garbage. He can't even be arsed to get the syntax highlighting right (actually, a good thing as it acts as a warning to gullible readers). But the best part is his code doesn't even work. He made an error – a semicolon where he wanted a comma – which means he couldn't even be arsed to check his own code.

Interestingly, and ironically, it also points to the main failing of his code: it adds needless complexity. Now he has to remember that the for loop uses semicolons and takes three "arguments", whereas his loop function uses commas and takes four arguments. Let's just kick that cognitive load up a bit. What could go wrong?

Clearly, the author has complete disregard for his audience, especially the most vulnerable members who might actually fall for this to their detriment.

Hmm. In retrospect, I am now thinking that I was way too nice in my comment.

Thread Thread
 
virtualmachine profile image
ByteCodeProcessor

OP is an adult not a child. a dumb idea is a dumb idea if one can say why it is a dumb idea.

Thread Thread
 
virtualmachine profile image
ByteCodeProcessor

OP is an adult not a child. a dumb idea is a dumb idea if one can say why it is a dumb idea.

Thread Thread
 
virtualmachine profile image
ByteCodeProcessor

OP is an adult not a child. a dumb idea is a dumb idea if one can say why it is a dumb idea.

Thread Thread
 
blindfish3 profile image
Ben Calder

I don't disagree with your assessment, or for the need to correct low quality posts, but I do think it's possible to do so in a constructive way and without resorting to petty insults 🤷

Collapse
 
tqbit profile image
tq-bit

Interesting Idea. You might even go one step further and make the whole function Promise based, given you're dealing with async tasks.

loop(...args).then(result => {})
Enter fullscreen mode Exit fullscreen mode

I noticed you have a small typo in your code here:

loop(3, n => n > 0; n => n - 1, console.log)
Enter fullscreen mode Exit fullscreen mode

After the second argument, there should be a comma instead of a semicolon

Collapse
 
lexlohr profile image
Alex Lohr

One thing that is usually confusing to beginners is that the update function will run after the body and before the subsequent test, so the order of execution would be:

for (
  /* Initialisation */;
  /* Test */;
  /* Update */
) { /* Body */ }
Enter fullscreen mode Exit fullscreen mode
  1. Initialisation
  2. Test (stop if condition is false)
  3. Body
  4. Update
  5. Jump to 2.
Collapse
 
michaeldelk profile image
Michael Delk

What timing! I have been doing barbells for a decade now and started reading Haverbeke's Eloquent Javascript a few weeks ago.

Weight training teaches patience as you apply principles to problems but have to delay the gratification of seeing the results. It also helps round out the body and minds daily experience as it complements a day of exercising the mind at a keyboard with exercise of the body (and both exercise a person's fortitude).

While I originally "learned" javascript back in the early 2000's as a way to manipulate web elements, now that I'm using the latest techniques to write full node apps, and B2B APIs, I find I have to approach this firehose of knowledge like I would a new 5x3x1 lifting cycle that will take a long time to complete and include many tweaks and adjustments along the way, strengthening supporting muscle groups to help shore sticking points in the full-body lifts. Good analogy. Just like weighted back extensions help a weak back when squats get heavy enough that you start doing inadvertent good mornings.

Collapse
 
shubhamk profile image
Shubham Kamath

Amazing article! It changed my perspective on how I looked at for loop.

It would be great if you could wrap the code in code blocks with three back ticks.

Collapse
 
charlesr1971 profile image
Charles Robertson

Interesting. By the way, your code snippets are not formatted?

Collapse
 
citronbrick profile image
CitronBrick

You can use

<3 backticks> javascript
your code
<3 backticks>

for JS syntax higlighting.

Collapse
 
icolomina profile image
Nacho Colomina Torregrosa

Fantastic! That's a really original approach.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.