I can't write a JavaScript for loop, and it does not matter

Search for a command to run...

Thank you for this article! I'm pleased to see I'm not the only one to not remember stuff considered basic. My favorite: finding out I've already upvoted the SO answer I'm looking for :)
Thanks 😉
Or finding that you actually answered the question you ask for 10 years ago 😅 as I've got 70k on Stackoverflow it actually happens 😄
This is one of the most stupid article I began to read (could not read until the end, too painfull).
There is a lot of uses for indexed array access (including, for instance, comparing or using two correlated arrays with only one loop, instead of a nested loop).
Using a function call requires stack manipulation, context switching, etc. Is slow as hell. Thousands of times slow (but don't trust me, do a test, as any scientific method requires).
You are just a bad programmer and hashnode just became a Medium competitor (in article quality).
I can indeed write for loops with indices if perf matters, but in most cases it's premature optimisation.
Do you always prematurely optimize? Do you feel a for loop is always the best solution for lists of size 10?
Ah good point. I guess my school teachers were using Java4 :D
Thanks :)
Thanks, forgot the tags :)
Hi everyone! Krzysztof and Tomasz from Software Mansion here 👋 It's been a fairly calm week for the React ecosystem, but not for the React Native world. Meta has made an exciting announcement about the release of React Native 0.80, where they've dec...

Hi everyone! This week is relatively calm in the React ecosystem, but we still have various interesting blog posts and releases. Maybe we'll soon get some exciting news from React Summit that's about on Friday! On the React Native side, all the devs ...

Hi everyone! I thought I was on schedule for today's issue, until I realized that Dan Abramov wrote 4 RSC blog posts this week 😂. We also get great releases, including Storybook, LiveStore, Base UI, and the Lingo Compiler is a quite exciting innovat...

Hi everyone! Cyril and Matthieu from Theodo Apps here 👋. This week, the Remix team announced some big news. Microsoft has also made it easier to try out TypeScript Go rewriting. In the React Native world, there were a few minor but interesting relea...

Hi everyone! This week, we're delighted to finally have a preview of React Server Components support in React Router. I've also found some very interesting PRs on the React repo, and give you a glimpse of what could be coming soon! The React Native e...

I've been using JavaScript daily for 7 years, and I'm not able to remember the syntax of a JavaScript for loop.
Despite this fact, I'm a rather successful freelance developer. Recently I even had the awesome opportunity to work for Facebook, as the Docusaurus lead maintainer, writing the code for the framework that powers the documentation sites of Babel, Prettier, Jest, ReactNative...
I'll explain why I'm not able to remember such syntax, and why it does not matter much.
TLDR: I'm a functional programmer
I've really started programming at the beginning of my engineer degree, around 2004 (before that, I was only able to hack some scripts for Counter-Strike console or IRC).
Most of our school teaching was based on Java, but we also saw a bit of C, C++, OCaml.
The first loop syntax I learned probably looked like this one:
List<Integer> numbers = Lists.newArrayList(1, 2, 3);
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers.get(i));
}
Before I came out of school, Java 6 brought some new, simpler syntax:
List<Integer> numbers = Lists.newArrayList(1, 2, 3);
for (Integer number : numbers) {
System.out.println(number);
}
At my first job, the Google Guava lib brought some new verbose functional syntax to Java, and I was able to do weird things with it 😅.
List<Integer> numbers = Lists.newArrayList(1, 2, 3);
Lists.newArrayList(Collections2.transform(numbers, new Function<Integer,Void>() {
@Override
public Void apply(Integer number) {
System.out.println(number);
return null;
}
}));
This Guava lib got me intrigued by functional programming, and lead me to become a Scala developer since 2012, and I was finally able to use functional programming concepts (loops, but not only) without the ugly Java/Guava syntax.
val numbers = List(1, 2, 3)
numbers.foreach(println)
In 2013, ReactJS came out, and this totally changed my career path. At this time, I didn't like JavaScript much and was only able to hack some inline JQuery things in server-rendered pages. But as a startup CTO, I saw my team struggle with architecture, BackboneJS and RequireJS, and thought I had to become better at frontend to lead them.
AngularJS looked like the safer choice at this time, but a Scala developer colleague really pushed for React, which looked fancy and risky. All things made sense with the visionary post of David Nolen (The Future of JavaScript MVC Frameworks), and we finally adopted React in January 2014, as it seemed we would be able to use our functional programming knowledge to the frontend app as well, and make the UI more predictable.
Fast forward, it wasn't easy to be a React early-adopter for our critical app. All companies were building their own state management solution, trying to figure things out, and so we did, based on the ideas of David Nolen to hold a single immutable state in an atom (I was able to get a hacky time-travel working before Redux).
Since then both the JavaScript language and the ReactJS ecosystem have progressed a lot, and it's very common to use functional programming principles nowadays.
As a long-time functional programmer, I simply don't write for loops very often.
Like anything you don't use regularly, you end up forgetting the syntax.
Today, many of us use ES5+ syntax (or Lodash/Ramda...) and some functional constructs. Using map, forEach, filter are the most illustrated examples in the JS community.
const numbers = [1, 2, 3]
numbers.forEach(number => console.log(number));
But we can go much further than that once we are more experienced with functional programming, and almost never write any for loops anymore.
Don't get me wrong, it's not necessarily a goal to not write for loops anymore, and I'm not telling you that you should remove all for loops of your production codebase.
Very often there's an alternative syntax possible for your loops that might be more expressive and easier to understand. After a while, you end up seeing a for loop as an implementation detail of a more elegant functional abstraction.
This more expressive syntax is not only for loops, and you can as well see a functional abstraction being an implementation detail of another higher-level abstraction.
Let's consider we want to increment the age of 2 brothers.
const brothers = {
id1: {name: "Sébastien", age: 34},
id2: {name: "Antoine", age: 23}
};
I very often see the array.reduce() operator used when a more expressive alternative was possible.
function incrementBrothersAges() {
return Object.entries(brothers)
.reduce((acc,[id,brother]) => {
acc[id] = {...brother, age: brother.age + 1};
return acc;
},{})
}
You know what? I really struggled to write this code.
My first attempt was not working at all (TypeScript would have helped).
function incrementBrothersAges() {
return Object.entries(brothers)
// acc is the first arg
.reduce(([id,brother], acc) => {
acc[id] = {...brother, age: brother.age + 1};
// we must return the acc here
},{});
}
Yet, writing this kind of transform is idiomatic for me, using higher-level functional programming abstractions, such as mapValues (included in lodash).
function incrementBrothersAges() {
return mapValues(
brothers,
brother => ({...brother, age: brother.age + 1})
);
}
And I think nobody would argue that this is harder to read and maintain right? If junior developers are not familiar with functional programming, they'll catch up fast and get used to it. This might even be harder to learn reduce.
I don't write for loops (or reduce), but I know the concepts. I know that these loops exist in different syntaxes, that can be useful for different use cases, and how to make a choice with a good tradeoff (performance, readability...).
I'll illustrate this with a concrete example from my daily work that actually led me to write this article.
I had this async function that performs some long task for a given country.
async function runCountryTask(country) {
// Simulate a long async task (1 to 5 seconds)
const taskDuration = 1000 + Math.random() * 4000;
await new Promise(resolve => setTimeout(resolve, taskDuration));
console.log(`Task completed for ${country}`);
}
This task had to be run for many countries, but the tasks should be run sequentially, not in parallel.
As I know the concepts, and I knew that the following would not work, as Promise.all would run all tasks in parallel.
async function runAllCountryTasks() {
const countries = ["FR", "EN", "US", "DE", "UK", "IT"];
// runs in parallel
await Promise.all(countries.map(runCountryTask))
}
I also knew that there were multiple possible solutions to solve this problem:
Promise.then() recursivelyI didn't want to introduce a new third party dependency just for a tiny utility function.
I also knew that using Promise.then() recursively could be harder to read, write, and maintain. There are many ways to write such a recursion, one of them could be:
async function forEachAsyncSequential(array, asyncFn) {
await array.reduce((acc, item) => {
return acc.then(() => asyncFn(item))
}, Promise.resolve());
}
So I opted for a basic for loop, as it seemed the right tradeoff.
As I'm totally unable to remember the syntax (in vs of, can I actually use const?), I had to actually google it, and it didn't take me long to be able to write the TypeScript code that will be shipped in production.
export async function forEachAsyncSequencial<T>(
array: T[],
asyncFn: (t: T) => Promise<void>,
): Promise<void> {
for (const item of array) {
await asyncFn(item);
}
}
async function runAllCountryTasks() {
const countries = ["FR", "EN", "US", "DE", "UK", "IT"];
// runs in sequence
await forEachAsyncSequencial(countries, runCountryTask);
}
Believe me or not, but I think It's the only for loop I actually wrote in JavaScript this year. And once it's written, I won't need to write it ever again (at least for this project), as it's now part of my functional programming abstractions, that I can reuse anywhere I need.
It's not very important to remember every syntax details to be productive in your daily work, particularly when you don't use them often (on purpose), as you prefer to work with more expressive, higher-level abstractions.
I had to google many things to write this article:
System.out.println accept an Integer?forEach in Guava (actually found my own StackOverflow question)array.reduce()Not remembering all this does not matter much, as long as I know what to look for.
In the same way, I don't know much about many other JavaScript things:
===, TypeScript... it's not worth knowing all of themThe knowledge and concepts you learn are more easily transposable from one language to another. I was able to learn React and contribute to its ecosystem quickly, thanks to my functional programming background.
I would argue that knowing how to do a recursive algorithm is more important than knowing the syntax of a for loop of a particular language. You will likely write many recursive algorithms in your career: the concept of recursion is not going anywhere anytime soon. But it's way more likely that you switch from one language to another from time to time.
Hopefully, writing this post will help me remember the syntax for a while until I forget it again 🤪.
🙏 If you like this post, please like it, share it or comment it 🙏:
For more content like this, subscribe to my mailing list and follow me on Twitter.