-1

I used to think that the scope of a variable declared with var covers the whole scope between the {} but i tried the following example and i would like an explanation please on why when i use 'i' inside the callback function for the onclick event listener the value is not the index of the for loop but the value of i once the for loop is finished.Thank you.

<html>
<head>
</head>
<body>
</body>
<script>
var components = ["1obj", "2obj", "3obj", "4obj", "5obj"];
createDivs(components);

function createDivs(components) {
    for (var i = 0; i < components.length; i++) {
        var image = document.createElement('div');
        image.innerHTML = components[i];
        image.index = i;
        image.onclick = function () {
            console.log(this.index); //gives the real index
            console.log(i); //gives the length of components+1
        };
        document.body.appendChild(image);
    }
}
</script>
</html>
Ali Chamas
  • 11
  • 1
  • 6
  • use let for expected result, check this link - https://stackoverflow.com/questions/32313961/let-vs-var-in-javascript-for-loops-does-it-mean-that-all-the-for-loops-usin – Naga Sai A Mar 08 '18 at 17:12
  • `this` changes inside the onclick function. It's a new scope. – jdmdevdotnet Mar 08 '18 at 17:17
  • Also i is the value of the last index because of lexical scoping. By the time the onclick happens, i will always be the last index. You can inject i in a closure. See my answer. – jdmdevdotnet Mar 08 '18 at 17:21
  • @Ali Chamas, did you check out my answer? – jdmdevdotnet Mar 08 '18 at 17:50
  • @jdmdevdotnet Yes i did thank you for your answer i marked it as the right one. Great explanation works perfectly. regarding this, i already stored the index value in .index so it works using this.index but your solution is better because it is the right way to do it without adding a new property that can be confusing later on. – Ali Chamas Mar 09 '18 at 14:14

2 Answers2

0

Your issue is closures, or lexical scoping . You're seeing i as the value of the last index because of lexical scoping. By the time the onclick happens, i will always be the last index. You can inject i in a closure, as such:

  (function(_i) {
    image.onclick = function () {
        console.log(this.index); //gives the real index
        console.log(_i); //gives the length of components+1
    };
  })(i);

see here for more information

jdmdevdotnet
  • 1
  • 2
  • 19
  • 50
0

All of the functions are referencing the same scope. It doesn't capture the current value and store a separate copy of the current value like you may think.

The solution is to use a function to set each variable so they each have a separate lexical environment.

webnetweaver
  • 192
  • 8