将循环中的计数器赋值给一个变量并不会保留它的当前值

Assigning the counter in a loop to a variable doesn't retain it's current value

本文关键字:变量 保留 一个 计数器 循环 赋值      更新时间:2023-09-26

我不理解下面的行为。

我希望下面的脚本做以下事情:

  1. 获取所有button类的元素
  2. 对于每个带有button的元素,分配一个onclick事件
  3. 当用户点击按钮时,当onclick被分配时,有一个带有i当前值的警报。

所以我希望点击"Button 1"会提示"I am Button 1"。

相反,所有3个按钮提示"我是按钮3"。看起来i计数器的值没有被保留。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Test</title>
    </head>
    <body>
        <p class="button">Button 0</p>
        <p class="button">Button 1</p>
        <p class="button">Button 2</p>
        <script>
            var buttons = document.getElementsByClassName('button');
            for (var i=0 ; i < buttons.length ; i++){
                buttons[i].onclick = function(){
                    alert("I am button " + i);
                };
            }
        </script>
    </body>
</html>

为什么会发生这种情况?我怎样才能达到我想要的行为?

试试这个。它被称为闭包。它捕获变量i,因为i在循环后没有被删除,所以它调用具有i当前值的事件处理程序。所以你需要一个局部变量,你可以通过执行函数得到它。因此,我创建了一个函数,将变量i传递给他,并且在函数作用域中,我有一个局部变量param,每次迭代都是新的。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Test</title>
    </head>
    <body>
        <p class="button">Button 0</p>
        <p class="button">Button 1</p>
        <p class="button">Button 2</p>
        <script>
            var buttons = document.getElementsByClassName('button');
            for (var i=0 ; i < buttons.length ; i++){
                buttons[i].onclick = (function(param){
                    return function(){
                    alert("I am button " + param);
                      };
                })(i);
            }
        </script>
    </body>
</html>

或者您可以使用ES6 feature let

<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <title>Test</title>
        </head>
        <body>
            <p class="button">Button 0</p>
            <p class="button">Button 1</p>
            <p class="button">Button 2</p>
            <script>
                var buttons = document.getElementsByClassName('button');
                for (let i = 0 ; i < buttons.length ; i++){
                    buttons[i].onclick = function(){
                        alert("I am button " + i);
                     }
                }
            </script>
        </body>
    </html>

回调button.onclick是一个闭包,它在堆栈中有对i变量的引用,该变量等于循环的最后一个值