1

I was interviewed for a JavaScript frontend developer position. I failed because I didn't know a few advanced questions. Please help me to understand at least this one.

My problem was on ECMAScript 6 knowledge, not the for loop in ECMAScript 5 or the closure. I didn't understand what is doing for/of or who is doing the magic in this ECMAScript 6 code to not overwrite the i.

The question was like:

To display numbers from 1 to 5 in the for loop, every time we click on a button, we have to wrap the console in a closure, to have the right output, so the i variable will not be overwritten if we use this closure.

In ECMAScript 6, in a for loop we only have the callback function, and i is not overwritten. Why?

// ECMAScript 5
for (var i = 0; i < 5; i++) {
  var btn = document.createElement('button');
  btn.appendChild(document.createTextNode('Button ' + i));
  btn.addEventListener('click',
    function(x) {
      return function() {
        console.log(x);
      };
    }(i)
  );
  document.body.appendChild(btn);
}

// ECMAScript 6
const ps = Array.from(document.querySelectorAll('p'));

for (const [i, paragraph] of ps.entries()) {
  paragraph.addEventListener('click', function() {
    return console.log(`${i+1}: ${this.textContent}`);
  });
 }
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Short answer is, because `var` is function scoped, meaning **only one `i`** is available in the closure of all event handlers, but `let` and `const` are block scoped, meaning there is **a unique `i`** available in the closure of each event handler. – nem035 May 09 '17 at 17:12
  • 1
    Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – nem035 May 09 '17 at 17:14
  • @nem you said "but let and const are block scoped, meaning there is a unique i available in the closure of each event handlers" in es6 for of I don't see any closure –  May 09 '17 at 17:18
  • in both examples, the anonymous function passed as the click handler callback has `i` available in its closure. – nem035 May 09 '17 at 17:19
  • 1
    Try using `var` instead of `const` in the `for..of`. The output will always show `total amount of paragraps: text content for specific paragraph` – nem035 May 09 '17 at 17:22
  • 1
    Oo, I can see clearly now :). I thought that for of does the whole job protecting i, but it's all about of const and let :). Thank you. –  May 09 '17 at 17:25
  • 1
    Nit: Their explanation of the ES5 solution is not quite correct. The solution to the loop problem is not the fact that a closure is used but that a *function is called* to create a new scope. Whether or not *that* function is a closure is irrelevant. – Felix Kling May 09 '17 at 20:29
  • 1
    It should read "we need to wrap the closure in an IIFE to create the scope", and the ES6 explanation would be that the closure is in the scope created by the block. – Bergi May 09 '17 at 21:33

1 Answers1

-2

This is just a matter of scope. It has nothing to do with the for...of loop...

Take a look at these scenarios:

var is global

// "i" is global
for (var i = 0; i < 5; i++) {}

console.log(i);

var is still global

// "i" is global
var i;
for (i = 0; i < 5; i++) {}

console.log(i);

let is local

// "i" is local
for (let i = 0; i < 5; i++) {}

console.log(i); // ReferenceError

let is global

// "i" is global
let i;
for (i = 0; i < 5; i++) {}

console.log(i);
Graham
  • 7,431
  • 18
  • 59
  • 84
Badacadabra
  • 8,043
  • 7
  • 28
  • 49
  • I see now that is not about for of loop. Their question was very very tricky. –  May 09 '17 at 17:31
  • From what I know, this is a common question in JavaScript interviews... ;) – Badacadabra May 09 '17 at 17:35
  • I did't know until now. I aspect it to ask me how you define vars in es6, but not putting this complicated code for just a simple basic knowledge about how you define variables :) –  May 09 '17 at 17:38
  • Notice that "let is local" is [a bit more complicated in loops](http://stackoverflow.com/a/30900289/1048572), though – Bergi May 09 '17 at 21:31
  • 2
    @Bergi: It is true, but I wanted to keep this answer simple. This is purposely not an in-depth answer and Dr. Axel Rauschmayer explains this better than I could: http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads – Badacadabra May 09 '17 at 22:05