简体   繁体   English

生成的回调函数的范围

[英]Scope in generated Callback function

I have a generater function generation callback functions for eventlisteners: 我有一个用于事件监听器的生成器函数生成回调函数:

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

The callback should just count how ofter a button was clicked. 回调应该只计算单击按钮的频率。 Lets generate two functions: 让我们生成两个函数:

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

And register them as listeners: 并将它们注册为侦听器:

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

Now I need a reset function: 现在我需要一个重置功能:

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

I would have expected, that the generator function passes the reference to the global counters into the generated callback functions and the callback functions would modifiy the global variables. 我曾期望,生成器函数将对全局计数器的引用传递到生成的回调函数中,并且回调函数将修改全局变量。 But they don't, as I learned from the reset function. 但是,正如我从重置功能中学到的那样,它们不是。

There is an issue with scope, but I do not get it. 范围存在问题,但我不明白。

  1. Why and how do the generated callback functions have an own scope for their counters? 为什么生成的回调函数及其计数器有自己的作用域?为什么? EDIT Answer: Because the argument counter passed into the createCallback function is not passed as refernce into the generated function. 编辑答案:因为传递给createCallback函数的参数counter没有作为引用传递给生成的函数。
  2. How could I bind/access the global counter1 and counter2? 如何绑定/访问全局counter1和counter2?

EDIT 编辑

  1. Since I already learned, that the 'counter' variable is not passed as reference: How can I generate a function with a reference to a global variable? 既然我已经知道了,那么'counter'变量不会作为引用传递:我如何生成一个引用全局变量的函数?

You can use an object to store the counters and pass property names around: 您可以使用一个对象来存储计数器并在以下位置传递属性名称:

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

(If you don't need individual names, use an array with indices instead) (如果不需要单独的名称,请改用带有索引的数组)

The alternative is to create multiple closures over the same variable for the different functionalities, and keep them in one object per counter. 另一种选择是在同一变量上为不同的功能创建多个闭包,并将其保留在每个计数器的一个对象中。 That's the OOP way: 这就是面向对象的方式:

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

(again, use an array of counters instead of multiple individually named variables if you need arbitrarily many) (同样,如果需要任意多个,请使用计数器数组而不是多个单独命名的变量)

Objects in JS are pased by reference (by reference value actually), so this will work ( setTimeouts are used here to simulate the callbacks) 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> 

In Javascript, primitive type variables like strings and numbers are always passed by value. 在Javascript中,原始类型变量(例如字符串和数字)始终按值传递。 So you could use object instead of primitive vars: 因此,您可以使用对象而不是原始变量:

Embed your global var inside an object: 将全局变量嵌入对象内:

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

Change your callback definition in this way: 通过以下方式更改您的回调定义:

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

Then create the callback vars: 然后创建回调变量:

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

And finally change the reset function: 最后更改重置功能:

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

Hope this helps! 希望这可以帮助!

The variable counter ( counter1 , counter2 ) is passed by value, bot by reference. 变量countercounter1counter2 )按值传递,按引用传递bot。 To make it work, the variables should be changed into objects: 为了使其工作,应将变量更改为对象:

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

Those can be passed into the generator function. 这些可以传递到生成器函数中。 The increment has to be changed accordingly: 增量必须相应地更改:

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

As well as the reset function: 以及重置功能:

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

Now it works. 现在可以了。

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

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