Search code examples
javascriptdictionaryfor-loopkey-valueundeclared-identifier

JavaScript Map or 2D Array for...of Variable Declarations or Lack Thereof


All the examples I find online for iterating over a Map using for...of are in this format:

for (const [key, val] of map)
    console.log(`${key} maps to ${val}`);

What about using previously declared variables? As in:

let key, val;
for ([key, val] of map)
    console.log(`${key} maps to ${val}`);

This works, but it also works if I never declare key or val, as in:

for ([key, val] of map)
    console.log(`${key} maps to ${val}`);

So in the second example, is the loop using the variables I declared, or is it implicitly declaring new ones within the scope of the loop? I'm not sure how much it matters, but I'd like to understand this all the same. I can't think of a way to test this that proves it one way or another, so I'm posing the question here. I'm probably just confused by the fact that I am enclosing the variables in brackets. In this example I am confident that my previously declared variable is the one being used in the loop, though I have no way to prove it:

let val;
for (val of array)
    console.log(val);

So I would guess that in the second example the loop is using my previously declared variables, but I'm just guessing. This [key, val] of syntax is novel to me and the docs and examples online don't touch on this aspect of it. The way JavaScript allows you to use undeclared variables, but seemingly only if you assign a value to them, is odd, and not a feature I plan to take advantage of any time soon.


Solution

  • When you declare loop variables outside a loop with let there's no problem of reusing them but that would be considered useless unless you want to handle the last values assigned to them in the loop.

    When you don't declare (define) the variables they will be considered as global (a property of the global object (window/globalThis)).

    But in the strict mode you will get an error. Using implicit global variables is NO-NO since you can share some variables between different code without knowing thus breaking these code pieces at runtime.

    That's why working in the strict mode is mandatory.

    To avoid run time errors use Eslint's no-undef rule:
    https://eslint.org/docs/latest/rules/no-undef

    <script>
    
      const map = new Map;
      map.set('test-key', 'test-val');
    
      for ([key, val] of map)
          console.log(`${key} maps to ${val}`);
    
      console.log('window.key', window.key);
      console.log('window.val', window.val);
    
    </script>
    
    <script>
    
    'use strict';
    
      const map2 = new Map;
      map2.set('test-key2', 'test-val2');
    
      for ([key2, val2] of map2)
          console.log(`${key2} maps to ${val2}`);
    
      console.log('window.key2', window.key2);
      console.log('window.val2', window.val2);
    
    </script>