具有相同功能的多个事件侦听器存储单独的局部变量?

Jon*_*aus 5

我对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()
Run Code Online (Sandbox Code Playgroud)
<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-->
Run Code Online (Sandbox Code Playgroud)

我可以看到,每次触发事件时,"点击"的值都会被更新和存储(可能是在事件处理函数返回?),但只是单击了相应的按钮.这些值是如何存储的,为什么不在两个事件处理程序之间共享它们?如果我希望在两个按钮之间共享"点击"的值,我是否需要在两者范围之外分配一个变量?

Jos*_*a K 4

你必须在'范围'中思考.当你打电话时,showClick()有一个范围.在此范围内,它会创建一个名为"click"的变量.此变量在此函数和所有子函数/闭包中有效.

该函数返回一个新函数,即所谓的闭包.此闭包可以访问封装函数的范围.每次调用showClick()新范围时都会生成并在此范围内生成变量clicks.此外,还创建并返回了闭包.范围,此范围内的变量和闭包不一样.每次调用showClicks时都会有所不同.

这就是他们为两个链接单独计算的原因.

如果您想同时计算两个点击次数......有多种解决方案.

  • 首先,你可以删除封闭.你不需要它.
  • 将闭包保存为showClick函数的上下文,并在每次调用showClick时使用它
  • 保存全局范围内的点击次数(不推荐)

编辑:在评论中提到两种方法来保存闭包并重用它:

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();
Run Code Online (Sandbox Code Playgroud)

2)"Singleton-Approach II"(保存clickcount)

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();
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)