0

I am a green-hand web programmer trying to binding onclick events functions to a series of components via a for loop and has tested it in chrome browser.

<!DOCTYPE html>
<html>
<head>
    <title>Onclick Test</title>
</head>
<body>
    <button id="button1">BUTTON</button>
    <button id="button2">BUTTON</button>
    <button id="button3">BUTTON</button>
    <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script type="text/javascript">
        for (var i = 0; i < document.getElementsByTagName('button').length; i++) {
            let g = () => console.log(i);

            document.getElementsByTagName('button')[i].onclick = g;

            g();
        }

        $(document).ready(() => {
            for (var i = 0; i < $('button').length; i++) {

                let f = () => console.log(i);

                f();

                $('button').eq(i).click(f);
            }
        });
    </script>
</body>
</html>

The console log shows that the onclick functions only take in the parameter 3. It seems that the browser has only fetched the loop index i as 3. I am in such a confuse. I wonder how does the onclick function in JavaScript work? And what is the scope for the variable i?

Here is the console log:

OnclickTest.html:13 0
OnclickTest.html:13 1
OnclickTest.html:13 2
OnclickTest.html:23 0
OnclickTest.html:23 1
OnclickTest.html:23 2
OnclickTest.html:13 3
OnclickTest.html:23 3
OnclickTest.html:13 3
OnclickTest.html:23 3
OnclickTest.html:13 3
OnclickTest.html:23 3

2 Answers2

0

Here i inside the onclick function is directly referring to the i outside the onclick handler. So when the i outside the onclick handler changes, the i inside the onclick handler changes too.

With getHandler method when i is passed into another function it is closed for modification so it will not change even if the bounding function changes the value.

JavaScript's scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function.

After the loop terminates, the function-level variable i has the value 3,
and that's what the inner function 'sees'. Refer the Answer to the question below

JavaScript closure inside loops – simple practical example

<script type="text/javascript">

     function getHandler(i){
       return function () {
            console.log(i);
         }
     }        

    for (var i = 0; i < document.getElementsByTagName('button').length; i++) {
        let g = getHandler(i);

        document.getElementsByTagName('button')[i].onclick = g;

        g();
    }

    $(document).ready(() => {
        for (var i = 0; i < $('button').length; i++) {

            let f = getHandler(i);

            f();

            $('button').eq(i).click(f);
        }
    });
</script>
Krishjs
  • 358
  • 2
  • 17
0

This happens because essentially you are attaching the same function g or f (in two different loops as seen in your code) as event listener to all the buttons. So irrespective of which button is clicked the same function is called which logs the i which was last set to the total number of buttons in case of your code it is 3.

You can use jQuery's index() method to get the desired result.

$(document).ready(() => {
  for (var i = 0; i < $('button').length; i++) {
    $('button').eq(i).click(function (){
      console.log($(this).index());
    });
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button1">BUTTON</button>
<button id="button2">BUTTON</button>
<button id="button3">BUTTON</button>
vatz88
  • 2,422
  • 2
  • 14
  • 25