在事件处理程序中关闭
Closure in event handler
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,仔细看了他们的解释,还是一头雾水
why the variable counter
get set to 0 when first click occurs.
那不是它被设置为 0 的时刻。当分配给 .onclick
时会发生这种情况。在那一刻 outer
被定义 并且 被执行。这就是 counter
设置为 0 的时刻。尚未处理任何点击。
only the function inner() get executed
确实如此。 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
的函数是 return 由 outer
编辑的函数,即 inner
.
另一种实现 counter
封装的方法:
function inner() {
this.counter++;
alert('Number of clicks: ' + this.counter);
}
element.onclick = inner.bind({ counter: 0 });
这里我们提供了一个未命名的对象,无论何时调用它,它总是作为 this
参数传递给 inner
。由于我们不在此构造之外保留对该对象的引用,因此我们实现了相同的原则:保持计数器的状态,但在处理程序之外无法访问。
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,仔细看了他们的解释,还是一头雾水
why the variable
counter
get set to 0 when first click occurs.
那不是它被设置为 0 的时刻。当分配给 .onclick
时会发生这种情况。在那一刻 outer
被定义 并且 被执行。这就是 counter
设置为 0 的时刻。尚未处理任何点击。
only the function inner() get executed
确实如此。 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
的函数是 return 由 outer
编辑的函数,即 inner
.
另一种实现 counter
封装的方法:
function inner() {
this.counter++;
alert('Number of clicks: ' + this.counter);
}
element.onclick = inner.bind({ counter: 0 });
这里我们提供了一个未命名的对象,无论何时调用它,它总是作为 this
参数传递给 inner
。由于我们不在此构造之外保留对该对象的引用,因此我们实现了相同的原则:保持计数器的状态,但在处理程序之外无法访问。