Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closure (let keyword) - Javascript [duplicate]

function first(){
    var items = document.getElementsByTagName("li");

    for(var x = 0; x < items.length; x++){
        items[x].onclick = function() {
            console.log(x);
        }
    }
}

function second(){
    var items = document.getElementsByTagName("li");

    for(var x = 0; x < items.length; x++){
        (function(val) {
            items[val].onclick = function() {
                console.log(val);
            }
        })(x);
    }
}

function third(){
    var items = document.getElementsByTagName("li");

    for(let x = 0; x < items.length; x++){
        items[x].onclick = function() {
            console.log(x);
        }
    }
}

There are 4 elements in the list. Outputs of the 3 functions:

first: 4 4 4 4
second: 0 1 2 3
third: 0 1 2 3

I am not able to understand the output from the third function. In the second function, each call to the IIFE creates a new function object and hence, a new val variable. But in the third function, there is a single copy of the variable x, then how is the output: 0 1 2 3

Please correct me if I am wrong.

like image 535
Shashank Shekhar Avatar asked Mar 02 '17 13:03

Shashank Shekhar


1 Answers

In the documentation for let from MDN they have an example covering this exact case in the Cleaner Code in inner functions section:

for (let i = 1; i <= 5; i++) {
  let item = document.createElement('li');
  item.appendChild(document.createTextNode('Item ' + i));

  item.onclick = function(ev) {
    console.log('Item ' + i + ' is clicked.');
  };
  list.appendChild(item);
}

The example above works as intended because the five instances of the (anonymous) inner function refer to five different instances of the variable i. Note that it does not work as intended if you replace let with var, since all of the inner functions would then return the same final value of i: 6. Also, we can keep the scope around the loop cleaner by moving the code that creates the new elements into the scope of each loop.

The same thing applies to your case, because you use let each anonymous function refers to a different instance of x. There is a different instance on each iteration of the loop. This happens because let has a block-level scope instead of the global function scope that var has.

like image 95
Spencer Wieczorek Avatar answered Oct 18 '22 16:10

Spencer Wieczorek