【问题标题】:JavaScript closure within eventlistener事件监听器中的 JavaScript 闭包
【发布时间】:2014-12-01 08:46:06
【问题描述】:
<button>test</button>
<button>test</button>
<button>test</button>
<button>test</button>
<button>test</button>
<script>
var nodes = document.getElementsByTagName('button');
function clicked(i){
    console.log('pass');

    // Closure
    // return function(){
    //  console.log(i);
    // }

}
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', clicked(i));
}
</script>

我正在尝试对 js 闭包有一个全面的了解,上面的函数甚至为按钮添加了监听器。它控制台记录“通过”5次,然后单击按钮时什么也不做。但如果我取消注释关闭位(返回),console.log 将回显 i,但不会记录“通过”。我确实找到了相关答案,但我不明白为什么关闭 onclick 在单击按钮时不会记录“pass”字符串,而是会注销 i。 p>

How do JavaScript closures work?

【问题讨论】:

    标签: javascript closures


    【解决方案1】:

    您在这里所做的是直接调用函数clicked,而不是将其设置为事件处理程序。

    我不明白为什么关闭 onclick 在单击按钮时不会记录“通过”字符串,而是会注销 i。

    嗯,你的关闭是

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

    为什么除了i 之外会记录任何内容?

    创建此闭包的函数应在页面初始化期间记录“pass”五次(因为您在循环中调用五次,每次记录一行并返回闭包)。

    你可以使用bind

    nodes[i].addEventListener('click', clicked.bind(nodes[i], i));
    

    这会给你i作为函数的参数,这样你就可以做

    console.log("pass", i);
    

    【讨论】:

    • 这个答案太棒了......你最后一次编辑让事情变得更加清晰。大号
    • 其实也可以使用 nodes[i].addEventListener('click', clicked.bind(nodes, i));
    • 是的。您可以将第一个参数设置为您想要的任何参数。它决定了this 将在您的事件处理程序内部(但您没有使用它)。您可以使用console.info(this) 对其进行测试。如果您想引用该 DOM 节点(读取属性或类似的东西),将其绑定到被单击的元素 (nodes[i]) 可能会派上用场。
    • ic,没错,我没用这个。再次感谢
    • @RobG:是的,这就是为什么我建议绑定到nodes[i],这是放置监听器的元素。
    【解决方案2】:

    正在尝试按要求回答原始问题...

    但我不明白为什么关闭 onclick 不记录“通过”字符串 当按钮单击而不是注销 i

    在没有注释掉的部分返回您的代码...

    <button>test</button>
    <button>test</button>
    <button>test</button>
    <button>test</button>
    <button>test</button>
    <script>
        var nodes = document.getElementsByTagName('button');
        function clicked(i) {
            console.log('pass');
    
             //Closure
             return function(){
              output(i);
             }
    
        }
        function output(i) {
            alert('The value of the closure i for this button is: '+i);
        }
        for (var i = 0; i < nodes.length; i++) {
            nodes[i].addEventListener('click', clicked(i));
        }
    </script>
    <style>
        html {
            counter-reset: button-count -1;
        }
    
        button:after {
            content: ' ' counter(button-count);
            counter-increment: button-count;
        }
    </style>
    

    (我还添加了一些额外的帮助解释)

    当您在for loop 中初始化事件侦听器时,您将传递clicked(i)返回值 作为在node[i] 上发生单击时要调用的函数指针。 在您的原始代码中,返回值是对 匿名函数 的引用,定义为:

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

    所以这是当你点击按钮 i 时执行的 - 不是 clickedclicked 仅在 for loop 期间执行。由于for loop,您将看到控制台中每个按钮的传递时间。

    匿名函数的词法范围包括它的包含函数clicked的范围,所以参数i在范围内 匿名函数。每次clicked 终止时,在for loop 期间,都会在参数i 上创建一个单独的闭包,以保留该特定调用的值。

    在上面的代码中,我创建了一个名为 output 的函数,它接收一个参数 i,所以这个

    function(){
      output(i);
    }
    

    ... 当您单击按钮 i 时调用:在 i 上也有一个关闭。

    我还添加了一些 CSS 样式来为按钮编号。

    【讨论】:

      猜你喜欢
      • 2016-03-11
      • 1970-01-01
      • 2020-06-21
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      相关资源
      最近更新 更多