Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

let keyword and closures?

I am learning about the new features in ES6. I have a question about let and it concerns this code:

for (let i = 0; i < 45; i++) {
    var div = document.createElement('div');
    div.onclick = function() {
        alert("you clicked on a box #" + i);
    };
    document.getElementsByTagName('section')[0].appendChild(div);
}

I am confused by this code. What is happening with that div object that is declared at the start of each loop? Is that a brand new, separate object each time, somehow enclosed in the block scope of i? Or is this div object being overwritten each pass through the loop and if so, how does it maintain it's connection to the i it is given via let?

like image 369
user4853 Avatar asked Jan 12 '16 17:01

user4853


People also ask

What is the let keyword used for?

The let keyword is used to declare variables in JavaScript. The var keyword can also be used to declare variables, but the key difference between them lies in their scopes. var is function scoped while let is block scoped - we will discuss this in more detail later.

Is let a keyword?

In JavaScript, let is a keyword that is used to declare a block scoped variable.

What is let keyword in angular?

The let keyword in Angular declares a template input variable that is referenced within the template. In Angular, the micro syntax is used to configure a directive in a compact and friendly string.

What is let keyword in ES6?

The let keyword was introduced in ES6 (2015). Variables defined with let cannot be Redeclared. Variables defined with let must be Declared before use. Variables defined with let have Block Scope.


2 Answers

When I like to get a better understanding of what's happening in ES6 code, I enter my Javascript into the BabelJS REPL.

Your code when entered into the REPL outputs:

'use strict';

var _loop = function (i) {
  div = document.createElement('div');

  div.onclick = function () {
    alert("you clicked on a box #" + i);
  };

  document.getElementsByTagName('section')[0].appendChild(div);
};

for (var i = 0; i < 45; i++) {
  var div;

  _loop(i);
};

Because you used let to assign i, its value is only available in the scope of the loop (or the function in the Babel example) for each loop iteration. To get the same functionality for the div variable, you could assign that variable in the loop body.

for (let div, i = 0; i < 45; i++) {
  div = document.createElement('div');
  ...
}

Lastly, about closures and holding on to the i variable, you're one step away from creating a closure to maintain the current i value for each div.

// Create a function to hold on to a specific number
function createOnClick(index) {
  return function() {
    alert("you clicked on a box #", index);
  };
};

// Assign the function to the element's action 
div.onClick = createOnClick(i);

Without the function factory, the onClick value would always get the maximum i value of 44. This is because the function is being run after the entire loop has iterated and i has stopped at i < 45.

like image 88
rxgx Avatar answered Nov 02 '22 09:11

rxgx


The <div> is a brand new object in each iteration, but it isn't enclosed in the block scope of i.

The function expression that is attached to the div is however also a brand new object, but this object is closing over i.

like image 29
Alnitak Avatar answered Nov 02 '22 10:11

Alnitak