Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Notifications
Mark all as read
Q&A

Does a for...of loop must contain a variable without assignment sign, and why?

+0
−4

The following code pattern reflects this answer.

This code contains a for...of loop:

for (const child of e.childNodes) {
  // Do stuff;
}

Does a for...of loop must contain a variable without assignment sign (=), and why?
Is there a way to achieve the same result with "regular" variable declaration?

Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

1 comment thread

There are no unnamed variables... (7 comments)

1 answer

+4
−0

Does a for...of loop must contain a variable without assignment sign (=)

Yes.

and why?

Because that's the syntax defined by the language specification. The people who defined it decided to do it that way.

Unless those people answer here (or we find a discussion about it somewhere, which I couldn't), we can only speculate why they have chosen this particular syntax instead of any other one.

In the comments, there's one argument against having a =: it would be confusing to have code like for (const variable = collection), because it looks like the whole collection is being assigned to variable. By making it for (const variable of collection), it avoids this confusion and makes it more clear that the variable is iterating through the collection's elements.

Of course this is debatable and each one will have their opinion about this being more clear or confusing. When I learned for..of, I was already familiar with similar constructs from another languages, so it wasn't confusing to me. But YMMV, as always.

I'd like to add that other languages have similar loops:

  • Java has the enhanced-for loop: for (Type variable : collection)
  • C# has the foreach loop: foreach (Type variable in collection)
  • Python uses a for..in loop: for variable in collection
  • PHP has the foreach loop, but the variable comes after the collection: foreach ($collection as $variable)
  • D also has foreach, but with a different syntax: foreach (variable; collection)

And so on, the list of syntax variations among different languages is huge. Just for the record, JavaScript also has for..in loops, with a similar syntax (for (const variable in collection)), but different behaviour.

Anyway, each language chooses whatever syntax they want to. The people who defines it might consider many factors to decide between one or another, and each language also has their own processes to discuss and decide it (such as PEP's for Python, JEP's for Java, TC39 for JS, etc). Sometimes the decision has a reasonable rationale, technical justifications, etc, but sometimes is just a matter of personal preference (I can't tell which one drove the decision of the for..of syntax, though).

Therefore, IMO the only reasonable answer to "Why does a for..of loop requires a specific syntax?" is simply "Because it was defined that way". To know why it was decided to use syntax A instead of B, we should ask to the people who made the decision (without that, the best we can do is only speculate).


Is there a way to achieve the same result with "regular" variable declaration?

Maybe, it depends on what the code does.

For a simple loop such as:

const collection = [ 1, 2, 3, 4, 5 ];
for (const variable of collection) {
    console.log(variable);
}

You could declare the variable outside the loop:

let variable;
for (variable of collection) {
    console.log(variable);
}

Although the "result" (AKA the output) is the same, there are some differences.

I can't use const in the second case, because the variable will be assigned a different value in each iteration.

And by not using const, this means that I could change its value inside the loop:

let variable;
for (variable of collection) {
    variable = 1000;
    console.log(variable);
}

If I use const and declare it inside the loop, though, I can't change its value:

for (const variable of collection) {
    variable = 1000; // error!
    console.log(variable);
}

This gives me an error because I can't assign another value to a const variable. That's useful if you want to make sure that the variable isn't changed inside the loop.

Another difference is that in the second code, the variable still exists after the loop:

let variable;
for (variable of collection) {
    console.log(variable);
}
console.log('after', variable); // variable has the value of the last collection's element

That's because it was declared outside the loop.

But if I do this:

for (const variable of collection) {
    console.log(variable);
}
console.log('after', variable); // error (variable is out of scope and doesn't exist outside the loop)

Now the variable's scope is the for..of loop, thus it can't be accessed outside the loop. That's useful to limit the variable's scope.


Of course you could also use a "traditional" for:

for (let i = 0; i < collection.length; i++) {
    const variable = collection[i];
    console.log(variable);
}

But the for..of loop is actually more than just an alternative syntax, because it allows you to loop through any iterable object.

Not all iterable objects have the length property, and some might not support the [] syntax to access a specific element. For those objects, the for..of loop provides a standard way to loop through them, all they have to do is implement the iterable protocol.

Just to provide some examples:

// A Set doesn't have a way to access individual elements by index
var set = new Set([1, 2, 3, 1, 4, 5]);
for (const n of set) {
    console.log(n);
}

// I can iterate through the keys and respective values of a Map
var map = new Map([ ['name', 'Douglas'], ['age', 42], ['country', 'UK']]);
// and I can also use destructuring assignment: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
for (const [key, value] of map.entries()) {
    console.log(`${key} = ${value}`);
}

And there are cases where the results are different, such as when looping through the characters of a string:

const string = 'abc' + String.fromCodePoint(0x1F60A);
for (const character of string) {
    console.log(character);
}

The output is (note the emoji in the end):

a
b
c
😊

But with a traditional for:

for (let i = 0; i < string.length; i++) {
    console.log(string[i]);
}

This will print:

a
b
c
�
�

That's because for..of loops through the Unicode code points, while the traditional loop breaks some of them in surrogate pairs. I know that's way beside the point, it was just to show that a for..of loop has its own characteristics, and sometimes there's no obvious equivalent using other types of loops (but if you're curious about all this Unicode stuff, take a look at this answer).


Summary

  • the for..of loop syntax is the way it is, because whoever designed it, decided it that way
  • some cases might be interchangeable with a traditional for loop, some other cases might not
Why does this post require moderator attention?
You might want to add some details to your flag.

1 comment thread

Comments (1 comment)

Sign up to answer this question »

This community is part of the Codidact network. We have other communities too — take a look!

You can also join us in chat!

Want to advertise this community? Use our templates!

Like what we're doing? Support us! Donate