DEV Community

Cover image for Stop using for loops. Here's why.

Stop using for loops. Here's why.

Jack Shen on March 02, 2020

It is current year new Date().getFullYear(), and still I still see many JavaScript devs using and even recommending the use of for loops. You yours...
Collapse
 
jkhaui profile image
Jordy Lee • Edited

... And it's articles like this that make me think we were better off before anyone could publish anything on the internet.

The main problem I have is your piece is actually well written, thus it is probably going to be taken as gospel by newbie devs.
I enjoy the ease of writing callback functions instead of for loops as much as anyone, but it is such a biased outlook to claim that this is always the right solution.

Why don't you mention the areas where imperative loops outshine higher order functions? E.g. the fact that a for loop is ~10x faster than a forEach callback

Collapse
 
jackshen profile image
Jack Shen

E.g. the fact that a for loop is ~10x faster than a forEach callback

I believe this is untrue. Can you substantiate this claim?

Collapse
 
jkhaui profile image
Jordy Lee • Edited

It's widely known that loops based on callback functions generally perform much worse than imperative loops. Here's an example, where forEach is 96% slower than a vanilla for loop: stackoverflow.com/questions/438217...

C'mon man, I appreciate that you want to share your knowledge, but if you are going to write posts with such provocative titles then you need to know this stuff. I am a big fan of functional programming and much prefer it over OOP, but the aspect I dislike most about FP is the performance hit from making everything immutable

Collapse
 
matgott profile image
matgott

Try yourself.

let arr = [];
for(x = 0; x < 100000; x++) {arr.push(Math.random());}

function oldFor(d) {
aux = [];
const t0 = performance.now();
for(x=0; x < d.length; x++) {
aux.push(d);
}
return (performance.now() - t0);
}

function eachFor(d) {
let aux = [];
const t0 = performance.now();
d.forEach(v => {
aux.push(v);
});
return (performance.now() - t0);
}

oldFor(arr);
eachFor(arr);

Thread Thread
 
joey542 profile image
joey542

Okay. This is your code in typescript with a 10M length array. The forEach time is double.
Image description

I made another for just testing the other loops with a 10M length array.
Image description

So... the conclusion is... If you want to loop through big arrays just use the old for loop. And I made an account just for to send this comment.

Collapse
 
davidjames profile image
DavidJames • Edited

wow, this is terrible. I'd suggest "deleting this post" if you were to ask.

Collapse
 
chechenev profile image
Maxim Chechenev • Edited

The title is so clickbait, it can confuse people a lot.

Your examples are not about "stop using" but about situations how/when to use filter, reduce, etc.

I think you should provide more specific examples and real life use cases to explain your opinion, otherwise it's a really bad advice.

Collapse
 
macsikora profile image
Pragmatic Maciej • Edited

I would like to filter all those kind of articles.

To be clear I appreciate your effort, but radical attitudes saying that you should not use x or y is harmful. Lately there was such attitude for not using reduce, and I don't agree with that in the same way I don't agree with your article.

Also I think you are by intention making such clickbait title.

Collapse
 
jkhaui profile image
Jordy Lee
const filterClickbaitArticles = () => fetch('https://dev.to/api/articles')
  .then((response) => {
    return response.json();
  })
  .then((articles) => {
    const BAD_ARTICLE_REGEX = /(why)(\b\s.*\s\b)(is bad)/gi;

    return articles.filter(title => !BAD_ARTICLE_REGEX.test(title));
  });

Collapse
 
macsikora profile image
Pragmatic Maciej

Good one 😁

Collapse
 
pavermakov profile image
Pavel Ermakov

If you are working with very large lists of data, the for loop shines like a diamond

Collapse
 
lluismf profile image
Lluís Josep Martínez

Or if you read a very big file, or a result set of unknown size.

 
idanarye profile image
Idan Arye

+1 about reduce. Consider #3 in dev.to/thejohnstew/5-programming-p...

const exampleValues = [2, 15, 8, 23, 1, 32];
const [truthyValues, falseyValues] = exampleValues.reduce((arrays, exampleValue) => {
  if (exampleValue > 10) {
    arrays[0].push(exampleValue);
    return arrays;
  }

  arrays[1].push(exampleValue);
  return arrays;
}, [[], []]);

It uses reduce to feel functional and hip, but in practice it just mutates the arrays and passing them as is (they are mutated, but it's the same reference) to the next iteration.

But even proper uses of fold/reduce are usually clearer and simpler when done with loops, because the whole point of reduce was to emulate foreach in purely functional languages.

Collapse
 
timhlm profile image
moth • Edited

All of these are tools that serve different purposes. A few points I'd like to make:

1.) Composition

The prototype methods map, filter, reduce are useful because they avoid side effects and mutation by returning a new instance of the array, but they're also composable (or chainable in this chase), arguably their biggest benefit.

The other methods, sort, every, and forEach are either not composable because they don't turn arrays, or they actually does mutate in place (which you do touch on in the article with forEach, much appreciated, but sort is the bigger offender).

2.) OG for loops are generally faster

hackernoon.com/javascript-performa...

Not only that, but they can take exponentially less resources. Imagine you have a data set of N objects, that all get mapped, filtered, and reduced via prototype methods. That's three new versions of your data of N length that have to be in memory now, and you've gone through the list 3 times. There're real performance implications to this. If you can do it with a for loop in one pass, that may be a better option in context.

3.) For...of

The new for...of operator is outstanding, and plays better with async/await than the array prototype methods. Take a composition function for example:

function compose(fxList =[]) {
  return async function (initialInput) {
    let aggregatedValue = initialInput
    for (const fx of fxList) {
      aggregatedValue = await fx(aggregatedValue)
    }
    return aggregatedValue
  }
}
Enter fullscreen mode Exit fullscreen mode

This is basically a reduce, but it is easier to understand and write with a for...of loop. Try an implement this with the reduce prototype method, and I think you will see that it's not as straightforward.

Not only that, but For...of's support iterables, one of JavaScript's most powerful features. To use Array prototype methods, you have to spread them across a new array and you lose the context about what the data structure was initially. You then lose all the benefits of them- whether it's a Set or Map or some custom iterable. To me, that's pigeonholing yourself to array features and JS will evolve past that.

Always appreciate a different opinion though. Thanks for writing this and starting the conversation!

Collapse
 
jserrao profile image
John Serrao

I actually enjoyed your piece. I think you're getting piled on.

There are good reasons to use .forEach(), for and while. Just remember, with forEach() it's just an abstraction - it's basically sugar on top of a for loop. This makes it quite a bit slower, but I'd agree syntax is often much cleaner.

Maybe unintentionally, you're veering into a larger discussion on performance and picking the right data structure to use in a given situation. You might want to follow this piece up with a part 2 where you analyze those further.

Collapse
 
blindfish3 profile image
Ben Calder

Agreed on most counts. You don't mention that for loops also allow you to break out of the loop early; which depending on context can provide performance benefits.

There is very little good usage for reduce.

On the contrary, there are some incredibly useful applications for reduce and it can often be used when a normal for loop seems like the only option.

Collapse
 
lluismf profile image
Lluís Josep Martínez

You can't use BREAK or CONTINUE in a foreach/filter/map etc. Normal for loops are there for a reason.

Collapse
 
jackshen profile image
Jack Shen

You shouldn't really stop using for loop, they are more flexible as they are more generalized and in some cases more readable than the prototype functions.

My point is that for loops shouldn't be the first solution, but rather used on a "as needed" basis. I acknowledge in my article there are circumstances where they may be preferable.

There is very little good usage for reduce.

Could you justify this statement?

Collapse
 
revenity profile image
Revenity • Edited

One problem with using syntatic sugar like these are people recreating a callback on each call of a function that contains a .map, .forEach or whatever.

function f(a) {
    a.forEach(item => { ... });
}
Enter fullscreen mode Exit fullscreen mode

Also for loop is significantly faster and more readable in most cases, if you know how to do it correctly.

// Not this (Rely on iterator protocol which is slow af)
for (const item of arr) {}

// This (Cache the length pls)
for (let i = 0, { length } = arr; i < length; ++i) {}
Enter fullscreen mode Exit fullscreen mode

Note for beginners: If you want to get good, try to understand what's going on under the hood.

Collapse
 
dexygen profile image
George Jempty • Edited

The blanket statement "stop using for loops" is just bad advice. There are plenty of times when they are the best solution, for instance when looping over a "stack" that can grow as you loop over it, see the following stack-overflow answer: stackoverflow.com/a/47889841/34806 Use them when they make sense, and don't use them when they don't, and if you don't know the difference, don't write posts about them

Collapse
 
kalium profile image
kalium.xyz

Nice article. You require for loops for situations where you have to adjust the current index of the loop or step by steps other than 1. Even when dealing with arrays, you don't always want to loop over the array item per item.

Collapse
 
jackshen profile image
Jack Shen

You raise a great point. As I said, sometimes you’ll have no choice but to use for loops. It’s up to us as devs to decide if and when they should be used. In the interest of minimising their use, it’s good to creatively explore alternatives.

Adjusting index is a tricky one -- my understanding is that if you want to do that as part of something like a binary search, there’s no real alternative to for loops. If you expect small input sizes, you could get away with Array.prototype.indexOf(): O(n) complexity vs O(log n) for a binary search.

Iterating by steps other than 1 is a bit easier. You can do this by chaining Array.prototype.filter() and Array.prototype.forEach():

const STEP_SIZE = 3;  

myArray
  .filter((element, index) => !(index % STEP_SIZE))
  .forEach(nthElement => {
    // Do stuff here
  });

Array.prototype.reduce() also works. Yes, element ends up being unused, but this is nonetheless preferable to using a for loop.

Collapse
 
edinhadzovic profile image
edinhadzovic

For loops are old school, and old school is sometimes still great :)

Collapse
 
theodesp profile image
Theofanis Despoudis • Edited

Plus all school books use only for loops in their examples anyway!

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
jkhaui profile image
Jordy Lee

All of us who appreciate non-clickbait should make our own Wikipedia-like platform where any inaccurate or clickbait articles are immediately deleted.

Collapse
 
chechenev profile image
Maxim Chechenev

Wow, that's so aggressive.

If I want clickbait titles I could open Medium and find hundreds of them. And it's very difficult to find a real useful article there. Do you want Dev.to to be same place?

Thread Thread
 
jkhaui profile image
Jordy Lee

You're right, dev.to is much better than medium. My comment here added no value to the discussion, apologies to OP.

Collapse
 
richfinelli profile image
Rich Finelli

I love this take. for loops are tough to read, albeit .forEach() is only slightly more readable. Most times for loops don't need to be replaced with forEach(), they can be replaced with a .map(), .filter(), etc and be much more readable, avoid mutation and allow your code to follow a more functional pattern. If you think your array methods are slowing down your app, consider swapping out with a traditional for loop, but i wouldn't pre-optimize this way at the expense of readability and maintainability. The key to web apps at scale is a maintainable code base which means its readable and intentions are clear. This allows team members to make changes quickly without fear of bugs.

Chances are that your array methods aren't what's making your app slow. Here are some common reasons your app is slow: netguru.com/blog/11-reasons-why-yo.... But, if you're dealing with a large data set, and the array methods are causing an unwanted delay, switch back to for loop.

Collapse
 
john_malone_97e041014f7a4 profile image
John Malone • Edited

So in summary: if there is a built in function to do what you want to do in your potential loop, then use it. That is, if someone else implemented your ugly for loop for you, then you don't need a for loop. If they did not, then...... what exactly? I have been programming for 20 years and have no idea what this discussion (that I've seen before on other sites) is actually about.

Collapse
 
belhassen07 profile image
Belhassen Chelbi

Stop saying things like this

Collapse
 
alexgmdev profile image
Alex Martin

Looks like you're getting a lot of heat here. But as a somewhat JS beginner it was nice to see the different array implementations compared to their respective loops.

Thanks for the write up.

Collapse
 
matgott profile image
matgott • Edited

The problem isn't the "different array implementations", title is the problem. Is intentionally bad to attract views, but send a wrong message.

.filter, .map, .sort are usefull tools, but FOR is better in terms of performarce. If you have a lot of data to process, FILTER will not be the best choice.

Nobody should stop using for loops.

Collapse
 
edwardmauthe profile image
EdwardMauthe

for(;;){}

Collapse
 
kimsean profile image
thedevkim

For loop for performance wise.

Collapse
 
theodesp profile image
Theofanis Despoudis

That looks alright with me!

Collapse
 
lehmannsystems profile image
Mike

This must be satire.