Javascript 多个具有相同函数的事件侦听器存储单独的局部变量?
我对javascript中的闭包相当陌生(当然是在将闭包应用于事件处理程序时!),并试图掌握导致此代码行为的基本原则:Javascript 多个具有相同函数的事件侦听器存储单独的局部变量?,javascript,closures,event-listener,local-variables,Javascript,Closures,Event Listener,Local Variables,我对javascript中的闭包相当陌生(当然是在将闭包应用于事件处理程序时!),并试图掌握导致此代码行为的基本原则: 函数showClick(){ var=0 返回函数(e){ 咔哒声++ log(“单击”+“单击”+[e.clientX,e.clientY]) 返回点击 } } document.getElementById(“b1”).onclick=showClick() document.getElementById(“b2”).onclick=showClick() 记录我的点击次
函数showClick(){
var=0
返回函数(e){
咔哒声++
log(“单击”+“单击”+[e.clientX,e.clientY])
返回点击
}
}
document.getElementById(“b1”).onclick=showClick()
document.getElementById(“b2”).onclick=showClick()
记录我的点击次数
记录我的点击次数
您正在创建函数的多个实例。这些实例中的每一个都有自己的点击次数
变量,这就是它们自己增加的原因。您有几种选择,其中包括:
保留对函数的引用:
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
将变量保持在全局范围内
function showClick() {
this.clicks = 0; // this === window here
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();
您将调用两次
showClick()
,并将每次调用的结果分配给相应的事件侦听器。下面是一个简单的方法:
函数showClick(){
var=0
返回函数(e){
咔哒声++
log(“单击”+“单击”+[e.clientX,e.clientY])
返回点击
}
}
var clickHandler1=showClick();
document.getElementById(“b1”).onclick=clickHandler1;
var clickHandler2=showClick();
document.getElementById(“b2”).onclick=clickHandler2;
下面是另一种看待它的方式:
document.getElementById(“b1”).onclick=(函数(){
var=0
返回函数(e){
咔哒声++
log(“单击”+“单击”+[e.clientX,e.clientY])
返回点击
}
})();
document.getElementById(“b2”).onclick=(function(){
var=0
返回函数(e){
咔哒声++
log(“单击”+“单击”+[e.clientX,e.clientY])
返回点击
}
})();
这些函数具有相同的函数定义,但它们不共享实例变量
如果要在两者之间共享变量,只需完全忘记工厂函数(注意,这不会调用函数,而是将函数分配给事件侦听器):
var clicks=0
功能显示单击(e){
咔哒声++
log(“单击”+“单击”+[e.clientX,e.clientY])
返回点击
}
document.getElementById(“b1”).onclick=showClick;
document.getElementById(“b2”).onclick=showClick;
你必须在“范围”中思考。调用showClick()
时,有一个作用域。在这个范围内,它创建了一个变量,称为“clicks”。此变量在此函数和所有子函数/闭包中有效
该函数返回一个新函数,即所谓的闭包。此闭包保持对封装函数范围的访问。每次调用showClick()
时,都会生成一个新的作用域,变量在此作用域内单击。此外,还有创建并返回的闭包。作用域、此作用域内的变量和闭包不相同。每次你叫showClicks都会有不同的结果
这就是为什么这两个链接分别计算的原因
如果你想同时计算两次点击次数。。。有多种解决方案
- 首先,您可以移除封口。你不需要它
- 将闭包另存为showClick函数的上下文,并在每次调用showClick时使用它
- 在全局范围内保存单击(不推荐)
编辑:与此处评论中的问题类似,有两种方法可以保存闭包并重新使用它:
1) “单例方法I”(保存闭包本身)
2) “单一方法II”(保存点击次数)
3) “上下文方法”(将闭包另存为工厂函数的上下文)
“这不会调用函数,而是将函数分配给事件侦听器。”这可能是我对事件处理程序中的内部函数如何工作的主要误解。谢谢你的澄清!示例2:您可以将clickcount保存为上下文,而不是使用匿名函数。要短一点示例3:在全局范围内单击
不是一个好主意。这里是包装匿名函数保持作用域干净的正确位置。同样:您可以将clickcount保存为上下文以避免此“问题”。作为对我的回答的回应:完全忘记工厂函数,阅读正确的命名(链接在我对您的评论的回应中)。外部函数是工厂函数,内部函数是闭包。另一个来源:,你可以在我的另一个回复中找到三个:)@JoshuaK Re:“全局范围”最终,在全局范围内应该很少运行。我假设所有这些都将被包装在某种函数中。回复:结束命名,很抱歉,由于某种原因,我的脑海中出现了这种情况。你说得对。我已经删除了我对你答案的评论,但由于投票锁定,我无法更改我的投票,除非以某种方式编辑你的帖子。@TinyGiant没问题:)谢谢。这发生在我们当中最好的人身上。this.clicks=0;//此===此处的窗口
不要将变量放入全局范围,不需要这样做。只需将它放在工厂函数上方的一个范围内。将“函数值”与公共变量链接对我来说非常有意义!但是,我不知道你可以这样使用“event”关键字,而不会有其他潜在的不良副作用。我想如果我用函数表达式“var showClick=function(){…}”来代替我原来的函数声明,它也同样有效。@JoshuaK当然,这只是为了说明目的。@JonathanStraus我刚刚意识到了事件
变量名!我会改变它。。。不,它也不起作用:如果你那样调用它,你仍然会实例化这个函数两次。@JoshuaK第二个要点听起来像是我要采取的方法,但是你可以吗
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();
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();
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();