【问题标题】:Closure in event handler事件处理程序中的关闭
【发布时间】:2021-11-18 18:30:45
【问题描述】:

var element = document.getElementById('test-button');

//event handler
element.onclick = (function outer() {

  var counter = 0;

  return function inner() {

    counter++;
    alert('Number of clicks: ' + counter);
  };
})();
<button id="test-button">Test</button>

我不明白为什么每次单击按钮时变量计数器都不会重置为0,或者当它被单击时,只有函数inner()被执行,那么为什么变量计数器被设置为0 第一次点击时。 代码来自这个link,仔细看了他们的解释,我还是一头雾水。

【问题讨论】:

  • 是的,您的事件处理程序是内部函数。外部函数仅在设置事件处理程序时执行。

标签: javascript closures eventhandler


【解决方案1】:

为什么变量counter在第一次点击时被设置为0。

这不是设置为 0 的时刻。这发生在分配给 .onclick 的时候。在那一刻,outer 被定义并执行。这就是 counter 设置为 0 的时刻。尚未处理任何点击。

只有函数 inner() 被执行

确实如此。 outer 仅在页面加载时执行主脚本时执行一次,然后再也不执行。 inner 是分配给onclick 的函数,因此具有事件处理程序的角色。 inner 可以访问在outer 中定义的counter,但outer 永远不会再次执行。

outer是所谓的立即执行函数。

作为比较:您可以使用此代码实现类似的效果:

var counter = 0;
element.onclick = function inner() {
    counter++;
    alert('Number of clicks: ' + counter);
};

...但现在的缺点是counter 是一个全局变量,可以通过其他代码进行更改。为了确保counter 仅可用于点击处理程序,为它创建了一个闭包,您也可以这样做:

function outer() {
    var counter = 0;
    element.onclick = function inner() {
        counter++;
        alert('Number of clicks: ' + counter);
    };
}
outer();

这里的缺点是outer 有一个所谓的副作用:它分配给element.onclick。这就是选择 return inner 并将其留给 outer 的调用者来处理它的原因,例如将其分配给.onclick。

然后我们得到这样的东西:

function outer() {
    var counter = 0;

    return function inner() {
        counter++;
        alert('Number of clicks: ' + counter);
    };
}

element.onclick = outer();

这与您的代码基本相同:首先定义函数,然后立即执行。分配给onclick 的函数是outer 返回的函数,即inner。

实现counter这种封装的另一种方式:

function inner() {
    this.counter++;
    alert('Number of clicks: ' + this.counter);
}

element.onclick = inner.bind({ counter: 0 });

这里我们提供了一个未命名的对象,无论何时调用它,它总是作为this-argument 传递给inner。由于我们没有在这个构造之外保留对该对象的引用,因此我们实现了相同的原则:保持计数器的状态,但在处理程序之外无法访问。

【讨论】:

  • 非常感谢您清晰透彻的解释!我现在知道了。当这个element.onclick = function inner() 部分在outer() 函数内时,我不知道你所说的“它分配给element.onclick”是什么意思,你能告诉我更多吗?
  • 所以,outer 立即被执行:你可以通过紧跟在其定义后面的一对括号 () 看到这一点。它有一个return 语句,它返回的值是inner 函数。这意味着执行outer 的这个who 表达式将返回inner,并被分配给element.onclick。
猜你喜欢
  • 2012-11-25
  • 1970-01-01
  • 2015-08-24
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-15
  • 1970-01-01
  • 2014-07-06
相关资源
最近更新 更多