39

I was reading this example of using a for.. of loop on a Map, and I was a bit confused with this syntax:

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");

for (var [key, value] of myMap) {
  console.log(key + " = " + value);
}

Specifically, I don't understand the array destructuring that is happening. I understand that you can use array destructuring to do something like let [one, two] = [1, 2];, but what is happening in this example? myMap isn't an array so why is this getting the correct values?

Another question I have is why is the order key, value in the destructuring, but when you do a forEach() the order is value, key, like here:

myMap.forEach((value, key) => {
  console.log(key + " = " + value);
});
0

4 Answers 4

58
for (var [key, value] of myMap) {
    console.log(key + " = " + value);
}

is like

for (let pair of myMap) {
    var [key, value] = pair;
    console.log(key + " = " + value);
}

So it’s not myMap that has to be an array for the destructuring to work; rather, each of its elements has to be an array when it’s iterated over, and iterating over a map indeed produces arrays (key/value pairs).

Map#forEach’s argument order is probably for consistency with Array#forEach, which calls the function with arguments (item, index); it, in turn, probably does that because you don’t always need the index.

Sign up to request clarification or add additional context in comments.

Comments

8

Slightly off topic but as an aside:

myMap.forEach((v,k) => {});

is about 50% more performant than

for (var [key, value] of myMap) {

}

so perhaps consider using Map.prototype.forEach (not to be confused with Array.prototype.forEach).

6 Comments

Doesn't it depend on the JS engine? Is it still true in 2021? Sounds like premature micro optimization.
Also awaiting async calls is difficult with .forEach but works out of the box with for ... of
@AgnosticMantis you are right if you want things to run in series, but in the off chance that you want them to run in parallel, then myMap.forEach(async (k,v) => await x(k,v)) would work fine
@Alexander Mills Yeah, that would work for that use-case. Though this will have a fire and forget behaviour. For running them in parallel and also being able to react on the result(s) I'd rather use something like Promise.all([...].map(async () => {...})).
Source for the performance advantage? I remember for of is always faster than forEach()?
|
2

myMap isn't an array so why is this getting the correct values?

Map's prototype has a [Symbol.iterator] property, which means instances of Map implement the iterator contract.

for of loops make use of iterators to loop over objects.

In other words, for of loops don't need arrays, they need iteratables. Arrays are just one type of iterable, maps are another.

In the case of maps the iterator yields a 2-element array consisting of key and value for each iteration. It also has additional methods that allow you to iterate over just the keys or the values.

Comments

-3

All, Allow me to add that how the asked syntax works.

The Map.entries() method returns a new Iterator object that contains the [key, value] pairs for each element in the Map object in insertion order.

for (var [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}

But in your question you haven't added .entries but still it works. The reason is the symbol.Iterator points by default to Map.prototype.entries() function. This is the reason you include or exclude it works both ways. As explained above the .entries() function returns an Iterator of array([key,value] pair).

2 Comments

The Map#entries method does NOT return an arrays. It returns an iterator that yields key value pairs, which can be consumed via for…of. You also forgot to call entries.
Thanks for correcting, On the top of explanation I have written clearly that it returns an iterator. I have edited the below statement as well. Request you to upvote me as my reply was missing in the discussion and is a value add.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.