繁体   English   中英

生成的回调函数的范围

[英]Scope in generated Callback function

我有一个用于事件监听器的生成器函数生成回调函数:

function createCallback(counter){
    return function(){
        counter++;
    }
}

回调应该只计算单击按钮的频率。 让我们生成两个函数:

var counter1 = 0; 
var counter2 = 0;
var callback1 = createCallback(counter1);
var callback2 = createCallback(counter2);

并将它们注册为侦听器:

button1.addEventListener("click", callback1);
button2.addEventListener("click", callback2);

现在我需要一个重置功能:

function reset(){
  counter1 = 0;
  counter2 = 0;
}

我曾期望,生成器函数将对全局计数器的引用传递到生成的回调函数中,并且回调函数将修改全局变量。 但是,正如我从重置功能中学到的那样,它们不是。

范围存在问题,但我不明白。

  1. 为什么生成的回调函数及其计数器有自己的作用域?为什么? 编辑答案:因为传递给createCallback函数的参数counter没有作为引用传递给生成的函数。
  2. 如何绑定/访问全局counter1和counter2?

编辑

  1. 既然我已经知道了,那么'counter'变量不会作为引用传递:我如何生成一个引用全局变量的函数?

您可以使用一个对象来存储计数器并在以下位置传递属性名称:

const counters = {
    a: 0,
    b: 0
};
function createCallback(counterName){
    return function(){
        counters[counterName]++;
    }
}
button1.addEventListener("click", createCallback("a"));
button2.addEventListener("click", createCallback("b"));
function reset(){
    counters.a = 0;
    counters.b = 0;
}

(如果不需要单独的名称,请改用带有索引的数组)

另一种选择是在同一变量上为不同的功能创建多个闭包,并将其保留在每个计数器的一个对象中。 这就是面向对象的方式:

function createCounter() {
    var counter = 0;
    return {
        getCount() {
            return counter;
        },
        reset() {
            counter = 0;
        },
        increment() {
            counter++;
        }
    };
}

const counter1 = createCounter();
const counter2 = createCounter();
button1.addEventListener("click", counter1.increment);
button2.addEventListener("click", counter2.increment);
function reset(){
    counter1.reset();
    counter2.reset();
}

(同样,如果需要任意多个,请使用计数器数组而不是多个单独命名的变量)

JS中的对象通过引用(实际上是通过引用值)进行粘贴,因此可以正常工作( setTimeouts用于模拟回调)

 function createCallback(counter){ return function(){ counter.count++; } } function reset(){ counter1.count = 0; counter2.count = 0; } var counter1 = {count: 0}; var counter2 = {count: 0}; var callback1 = createCallback(counter1); var callback2 = createCallback(counter2); setTimeout(function(){ callback1(); document.getElementById('result').innerHTML += counter1.count + ' '; }, 1000); setTimeout(function(){ callback1(); document.getElementById('result').innerHTML += counter1.count + ' '; }, 2000); setTimeout(function(){ callback1(); document.getElementById('result').innerHTML += counter1.count + ' '; }, 3000); setTimeout(function(){ reset(); document.getElementById('result').innerHTML += counter1.count + ' '; }, 4000); 
 <div id="result"></div> 

在Javascript中,原始类型变量(例如字符串和数字)始终按值传递。 因此,您可以使用对象而不是原始变量:

将全局变量嵌入对象内:

var myCounterObj = {
    counter1: 0, 
    counter2: 0
}

通过以下方式更改您的回调定义:

function createCallback(counter, name) {
    return function() {
        counter[name]++;
        console.log("My counter is: " + counter[name]);
    }
}

然后创建回调变量:

var callback1 = createCallback(myCounterObj, 'counter1');
var callback2 = createCallback(myCounterObj, 'counter2');

最后更改重置功能:

function reset() {
    myCounterObj.counter1 = 0;
    myCounterObj.counter2 = 0;
}

希望这可以帮助!

变量countercounter1counter2 )按值传递,按引用传递bot。 为了使其工作,应将变量更改为对象:

var counter1 = {"value": 0};
var counter2 = {"value": 0};

这些可以传递到生成器函数中。 增量必须相应地更改:

function generate(counter){
  return function(){
    counter.value++;
  }
}

以及重置功能:

function reset(){
  counter1.value = 0;
  counter2.value = 0;
}

现在可以了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM