生成回调函数的范围

时间:2017-11-09 09:49:24

标签: javascript

我有一个用于eventlisteners的generater函数生成回调函数:

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. 生成的回调函数为什么以及如何为其计数器设置自己的范围? 编辑答案:因为传递给counter函数的参数createCallback未作为参考传递给生成的函数。
  2. 我如何绑定/访问全局counter1和counter2?
  3. 修改

    1. 自从我已经了解到,'计数器'变量不作为参考传递:如何生成一个引用全局变量的函数?

4 个答案:

答案 0 :(得分:2)

您可以使用对象存储计数器并传递属性名称:

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;
}

(如果您不需要个人姓名,请使用带索引的数组)

另一种方法是在同一个变量上为不同的功能创建多个闭包,并将它们保存在每个计数器的一个对象中。这是OOP的方式:

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();
}

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

答案 1 :(得分:2)

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>

答案 2 :(得分:1)

在Javascript中,字符串和数字等基本类型变量总是按值传递。 所以你可以使用object而不是原始vars:

将全局变量嵌入对象:

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;
}

希望这有帮助!

答案 3 :(得分:-1)

变量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;
}

现在可行。