I Hate JavaScript』s for loops. Let Me Tell You Why.

收藏待读

I Hate JavaScript』s for loops. Let Me Tell You Why.

I Hate JavaScript』s for loops. Let Me Tell You Why.

I Hate JavaScript』s for loops. Let Me Tell You Why.I Hate JavaScript』s for loops. Let Me Tell You Why.

I hate the for loop and I think it』s a terrible construct. Let me tell you why…

Even though this is a clearly biased hit piece, there is actually a ton of really good info about JavaScript』s for loop .

note: This gripe is limited to only JavaScript』s for loops.

Deconstructing The For Loop

First, let』s have a look at the for loop. Now I mean a really good look. Let』s inspect every nook and cranny so we get a crystal clear understanding of what this monstrosity truly is.

The for loop consist of 4 major parts. Well, technically 5, but you should never use a label, so I』m just gonna tag this as :skull:. The 4th part also contains a couple of additional optional sub-parts.

I Hate JavaScript』s for loops. Let Me Tell You Why.

(:skull:) label — used for custom breaking. It is considered an anti-pattern to use labels, so just don』t.

(1) initialization — Runs one time before the loop begins.

(2) conditional — Runs before each iteration. This is where any break should happen.

(3) iteration – Runs after each iteration. Typically used to increment a counter.

(4) statements – This is where your code lives.

(4.1) continue (optional) – Will stop executing statements and proceed to the next iteration.

(4.2) break (optional) – Will stop executing statements and exit the for loop.

Meet Bit』s component platform

Bit (open source) helps your team organize, share and reuse components to build multiple projects and apps faster. Share components from your code, make them discoverable and use them anywhere. Give it a try.

But Wait… There』s More!

JavaScript doesn』t have just one for loop. JavaScript actually has three different for loops .

You can use a "for/in" loop to iterate over the keys of an array.

I Hate JavaScript』s for loops. Let Me Tell You Why.

You have to be careful with this one because it iterates over the keys and not the values. If you expected the output of this to be odd , even , odd , you’d be in for a surprise.

JavaScript』s for/in also doesn’t work the same way C#’s foreach/in loop works. So that is gonna be confusing.

I Hate JavaScript』s for loops. Let Me Tell You Why.

You can use a "for/of" to iterate over the values of an array or iterable.

I Hate JavaScript』s for loops. Let Me Tell You Why.

You have to be careful with this one because it iterates over the keys and not the values. If you expected the output of this to be odd , even , odd , you’d be in for a surprise.

JavaScript』s for/in also doesn’t work the same way C#’s foreach/in loop works. So that is gonna be confusing.

I Hate JavaScript』s for loops. Let Me Tell You Why.

You can use a "for/of" to iterate over the values of an array or iterable.

I Hate JavaScript』s for loops. Let Me Tell You Why.

Pro tip: You can iterate over the keys and values like this:

I Hate JavaScript』s for loops. Let Me Tell You Why.

var vs let

Another thing you have always have to keep in mind when writing for loops is that they will behave differently based on whether you use var or let .

When initialized with a var , the value(s) will be available outside of the loop.

I Hate JavaScript』s for loops. Let Me Tell You Why.

When initialized with a let , the value(s) will be constrained to the loop.

I Hate JavaScript』s for loops. Let Me Tell You Why.

var vs let

Another thing you have always have to keep in mind when writing for loops is that they will behave differently based on whether you use var or let .

When initialized with a var , the value(s) will be available outside of the loop.

I Hate JavaScript』s for loops. Let Me Tell You Why.

When initialized with a let , the value(s) will be constrained to the loop.

I Hate JavaScript』s for loops. Let Me Tell You Why.

Breakdown of Operations

Now I am going to break down the operations of the for loop. This way we』ll get a better understanding of what how it operates under the hood.

let』s start with a simple for loop example:

I Hate JavaScript』s for loops. Let Me Tell You Why.

What the above code does in pseudo-code:

I Hate JavaScript』s for loops. Let Me Tell You Why.

Take notice of the last 2 statements (line 12 and 13), specifically i++ . This is the reason why in the var and let section, the last console.log output end: 3 .

Initialization and Iteration

The initialization statement runs before the for loop begins and the iteration runs after the statements are run.

I Hate JavaScript』s for loops. Let Me Tell You Why.

What the above code does in pseudo-code:

I Hate JavaScript』s for loops. Let Me Tell You Why.

Take notice of the last 2 statements (line 12 and 13), specifically i++ . This is the reason why in the var and let section, the last console.log output end: 3 .

Initialization and Iteration

The initialization statement runs before the for loop begins and the iteration runs after the statements are run.

I Hate JavaScript』s for loops. Let Me Tell You Why.

But if I want to run a statement before the for loop, I can just write a statement before the loop. Also, if I want to run a statement after each iteration, I can just add it to the end of the statements.

I Hate JavaScript』s for loops. Let Me Tell You Why.

But for (; i < array.length;) looks silly. I could just shorten this to while (i < array.length) .

I Hate JavaScript』s for loops. Let Me Tell You Why.

So then explain to me why my first go-to is a for loop and not a while?

Note: let operates differently as the value is scoped to the loop.

Let』s Get Weird :stuck_out_tongue_winking_eye:

The for loop』s initialization, conditional, and iteration are statements. They can be any statements, and when I say any statements… I mean any statements .

So now I can write an insane for loop like this:

Press run on this monstrosity to see what happens.

Homework: Refactor the code above to execute the for loop using functions for init , conditional , post , and statements .

I Hate JavaScript』s for loops. Let Me Tell You Why.

But for (; i < array.length;) looks silly. I could just shorten this to while (i < array.length) .

I Hate JavaScript』s for loops. Let Me Tell You Why.

So then explain to me why my first go-to is a for loop and not a while?

Note: let operates differently as the value is scoped to the loop.

Let』s Get Weird :stuck_out_tongue_winking_eye:

The for loop』s initialization, conditional, and iteration are statements. They can be any statements, and when I say any statements… I mean any statements .

So now I can write an insane for loop like this:

Press run on this monstrosity to see what happens.

Homework: Refactor the code above to execute the for loop using functions for init , conditional , post , and statements .

I Hate JavaScript』s for loops. Let Me Tell You Why.

Immutability & Side Effects

Functional programmers dislike the for loop because it is by nature impure. Whenever I spot a for loop, my brain signals :warning: Danger , because I know I am about to see mutations and side-effects.

I Hate JavaScript』s for loops. Let Me Tell You Why.

It is not possible to add the values with a for loop in an immutable way.

It is impossible for a for loop to be pure.

We are bad at it

In this example, why does sum live outside of the loop?

I Hate JavaScript』s for loops. Let Me Tell You Why.

The for loop contains an initialization section, so why not include sum in the initialization section?

I Hate JavaScript』s for loops. Let Me Tell You Why.

It is not possible to add the values with a for loop in an immutable way.

It is impossible for a for loop to be pure.

We are bad at it

In this example, why does sum live outside of the loop?

I Hate JavaScript』s for loops. Let Me Tell You Why.

The for loop contains an initialization section, so why not include sum in the initialization section?

I Hate JavaScript』s for loops. Let Me Tell You Why.

Why do we use break instead of using the conditional . That is the conditional ‘s entire purpose after all!

I Hate JavaScript』s for loops. Let Me Tell You Why.

This is similar to writing nested if statement when you should be combining them into one:

I Hate JavaScript』s for loops. Let Me Tell You Why.

Both of these are arguably better options because the break happens in a single place, but we’ll see the code written “crazy style” 99.9% of the time.

And why do we write i++ instead of ++i when ++i is more intuitive?

I Hate JavaScript』s for loops. Let Me Tell You Why.

This is similar to writing nested if statement when you should be combining them into one:

I Hate JavaScript』s for loops. Let Me Tell You Why.

Both of these are arguably better options because the break happens in a single place, but we’ll see the code written “crazy style” 99.9% of the time.

And why do we write i++ instead of ++i when ++i is more intuitive?

I Hate JavaScript』s for loops. Let Me Tell You Why.

Familiarity Bias & The Mere Exposure Effect

The mere-exposure effect is a psychological phenomenon by which people tend to develop a preference for things merely because they are familiar with them.

The for loop consists of about 7 parts, but 3 of which are optional and infrequently used. The for loop is the most complicated construct we have in our language.

Yet a lot of programmers love it and actually prefer it over alternatives like map , filter and reduce .

Though, I find this much easier to read…

I Hate JavaScript』s for loops. Let Me Tell You Why.

… when compared a for loop.

I Hate JavaScript』s for loops. Let Me Tell You Why.

The for loop requires I me to read its contents to determine what is happening. You could add a comment to improve readability. But I would prefer the code to be readable without the need for comments.

I would hypothesize the reason for a preference for the for loop is due to a familiarity bias. A bias, due to us being taught for loops first. A bias built over years and years of use. But just a bias.

Solutions

At this point, you must be tired of me complaining and want to see some solutions.

Solution #1: Wrap it up!

The 「least amount of work」 solution is to wrap it up!

I Hate JavaScript』s for loops. Let Me Tell You Why.

… when compared a for loop.

I Hate JavaScript』s for loops. Let Me Tell You Why.

The for loop requires I me to read its contents to determine what is happening. You could add a comment to improve readability. But I would prefer the code to be readable without the need for comments.

I would hypothesize the reason for a preference for the for loop is due to a familiarity bias. A bias, due to us being taught for loops first. A bias built over years and years of use. But just a bias.

Solutions

At this point, you must be tired of me complaining and want to see some solutions.

Solution #1: Wrap it up!

The 「least amount of work」 solution is to wrap it up!

I Hate JavaScript』s for loops. Let Me Tell You Why.

A for loop itself might not be pure, but wrapping it in a function could result in a pure function.

I would go so far as to suggest all for loops should be wrapped in a function .

Use Map/Filter/Reduce

This is my favorite option. Switch to using map , filter , and reduce .

I Hate JavaScript』s for loops. Let Me Tell You Why.

Use a library

Use a library like Ramda that has even more functions like reduceWhile for when you need to control the iteration break.

But What About Performance?

I hear this all the time, 「a for loop is faster than a forEach so why shouldn』t I always use the faster option?」

Asking about performance is a great question! Fortunately, there is no real-world performance difference between a for loop and map/filter/reduce .

You might be tempted to run over to jsperf.com and start pasting metrics. But metrics from jsperf are not only meaningless (in 99.99% of applications) but you are probably measuring the wrong metrics.

To prove my argument,

I Hate JavaScript』s for loops. Let Me Tell You Why.

If you were to rely on these metrics, you would be lead to believe that you should use +"10" over parseInt("10", 10) because of the 64% speed improvement.

This is nothing more than a

Use a library

Use a library like Ramda that has even more functions like reduceWhile for when you need to control the iteration break.

But What About Performance?

I hear this all the time, 「a for loop is faster than a forEach so why shouldn』t I always use the faster option?」

Asking about performance is a great question! Fortunately, there is no real-world performance difference between a for loop and map/filter/reduce .

You might be tempted to run over to jsperf.com and start pasting metrics. But metrics from jsperf are not only meaningless (in 99.99% of applications) but you are probably measuring the wrong metrics.

To prove my argument,

I Hate JavaScript』s for loops. Let Me Tell You Why.

If you were to rely on these metrics, you would be lead to believe that you should use +"10" over parseInt("10", 10) because of the 64% speed improvement.

This is nothing more than a Red Hearing .

While this isolated section of your code will be 64% faster, this section is already so fast that the 64% is meaningless. This 「improvement」 you make will result in your application running 0.00ms faster . That』s right, your application will run at the same exact speed with no improvement.

You are much better off looking at the Big-O Notation, Cyclomatic Complexity, API latency, or caching to actualize real-world speed improvements.

Only after you have identified that section of your code as the bottleneck should you consider refactoring it. Premature optimization is the root of all evil .

To Summarize

JavaScript has not one, but three for loops. The most common for loop consists of 7 parts, 2 of which are optional, and 1 which should never be used. The for/in loop works differently than other languages like C#. The for loop can never be pure, being filled with either mutations, side effects, or both. Finally, the readability on a for loop is poor, requiring you to visually parse the entire for loop before you can understand its purpose.

Now in all fairness, I still do write for loops. But only when all other options fail . And the times I do write a for loop is becoming increasingly rare.

I do imagine a better world where the for loop does not exist.

Ask me stuff

I write about awesome fp stuff. Follow me to be in the know. You can also find me on Twitter @joelnet . I』m friendly, ask me questions in the comments!

I Hate JavaScript』s for loops. Let Me Tell You Why.I Hate JavaScript』s for loops. Let Me Tell You Why.
Cheers!

原文 : Bits And Pieces