我对javascript中的闭包很新(当然在将它们应用于事件处理程序时!),并试图掌握导致此代码行为的基本原则:
function showClick() {
var clicks = 0
return function(e) {
clicks++
console.log("click "+clicks+" at "+[e.clientX,e.clientY])
return clicks
}
}
document.getElementById("b1").onclick=showClick()
document.getElementById("b2").onclick=showClick()

<button id="b1">Record my Clicks</button> <!--only stores click history of b1, disregarding b2-->
<button id="b2">Record MY Clicks</button> <!--only stores click history of b2, disregarding b1-->
&#13;
我可以看到&#34;点击&#34;每次我触发事件时,是否正在更新和存储(可能在事件处理函数返回?),但仅对单击的相应按钮执行此操作。如何存储这些值,以及为什么它们不能在两个事件处理程序之间共享?如果我想要&#34;点击&#34;的值,我是否需要在两者范围之外分配一个变量?两个按钮之间共享?
答案 0 :(得分:5)
你必须在'范围'中思考。当你致电showClick()
时,有一个范围。在此范围内,它会创建一个名为“click”的变量。此变量在此函数和所有子函数/闭包中有效。
该函数返回一个新函数,即所谓的闭包。此闭包可以访问封装函数的范围。每当您调用showClick()
时,都会生成一个新范围,并且在此范围内变量clicks
。此外,还创建并返回了闭包。范围,此范围内的变量和闭包不一样。每次调用showClicks都会有所不同。
这就是他们为两个链接单独计算的原因。
如果您想同时计算两次点击次数......有多种解决方案。
编辑:在评论中提到了两种保存闭包并重复使用的方法:
1)“Singleton-Approach I”(保存闭包本身)
function showClick() {
if(showClick.closure) return showClick.closure;
var clicks = 0;
return showClick.closure = function(evt) {
clicks++;
console.log(clicks+' at '+evt.clientX+' / '+evt.clientY);
}
}
document.getElementsByTagName('a')[0].onclick = showClick();
document.getElementsByTagName('a')[1].onclick = showClick();
2)“Singleton-Approach II”(保存点击次数)
function showClick() {
showClick.clicks = showClick.clicks || 0;
return function(evt) {
showClick.clicks++;
console.log(showClick.clicks+' at '+evt.clientX+' / '+evt.clientY);
}
}
document.getElementsByTagName('a')[0].onclick = showClick();
document.getElementsByTagName('a')[1].onclick = showClick();
3)“上下文方法”(将闭包保存为工厂函数的上下文)
var showClick = (function showClick() {
return this;
}).bind((function() {
var clicks = 0;
return function(evt) {
clicks++;
console.log(clicks+' at '+evt.clientX+' / '+evt.clientY);
};
})());
document.getElementsByTagName('a')[0].onclick = showClick();
document.getElementsByTagName('a')[1].onclick = showClick();
答案 1 :(得分:2)
您正在创建该函数的多个实例。这些实例中的每一个都有自己的>>> sum(all(sublist[2] == 4 for sublist in lst) for lst in lists)
3
变量,这就是他们自己增加的原因。你有几个选择,其中包括:
保留对该功能的引用:
clicks
将变量保留在全局范围内
function showClick() {
var clicks = 0;
return function(e) {
clicks++
console.log("click "+clicks+" at "+[e.clientX,e.clientY])
return clicks
}
}
var clickEvent = showClick(); // we instance the function only once
document.getElementById("b1").onclick=clickEvent; // and use it here
document.getElementById("b2").onclick=clickEvent; // and here
答案 2 :(得分:1)
您已经两次调用showClick()
,并将每次调用的结果分配给其各自的事件侦听器。这是一个简单的方法:
function showClick() {
var clicks = 0
return function(e) {
clicks++
console.log("click "+clicks+" at "+[e.clientX,e.clientY])
return clicks
}
}
var clickHandler1 = showClick();
document.getElementById("b1").onclick=clickHandler1;
var clickHandler2 = showClick();
document.getElementById("b2").onclick=clickHandler2;
以下是另一种观察方式:
document.getElementById("b1").onclick=(function() {
var clicks = 0
return function(e) {
clicks++
console.log("click "+clicks+" at "+[e.clientX,e.clientY])
return clicks
}
})();
document.getElementById("b2").onclick=(function() {
var clicks = 0
return function(e) {
clicks++
console.log("click "+clicks+" at "+[e.clientX,e.clientY])
return clicks
}
})();
这些函数具有相同的函数定义,但它们不共享实例变量。
如果你想在两者之间共享变量,只需完全忘记工厂函数(注意,这不会调用函数,它会将函数分配给事件监听器):
var clicks = 0
function showClick(e) {
clicks++
console.log("click "+clicks+" at "+[e.clientX,e.clientY])
return clicks
}
document.getElementById("b1").onclick=showClick;
document.getElementById("b2").onclick=showClick;