简体   繁体   中英

Can you reset a variable that stores the result of calling a function containing a closure?

Is it possible to reset a variable that calls a function containing a closure? In the example below, this would be counter . (Be advised I'm new to closures so some of the comments might be wrong.)

function makeCounter() {
 let count = 0;
 return function() {
   ++count;
   return `count equals ${count}`; 
 };
};

// If you just call it two times without storing the result in a variable, count is reset to zero each time
console.log(makeCounter()()); // count equals 1
console.log(makeCounter()()); // count equals 1

// Since the counter variable holds a reference to the result of the outer function's call (which is the inner returned function, which "closes over" count), the JavaScript engine won't wipe it from memory.
let counter = makeCounter();

// As expected, calling counter again updates it (storing the updated count value)
console.log(counter()); // count equals 1
console.log(counter()); // count equals 2 <-- Can you reset count as stored in counter?

With that code, it is not possible to reset count variable in any way, that's the power of closures.

What you can do is modify counter, and implement a method reset

 function makeCounter() { let count = 0; const counter = function() { ++count; return `count equals ${count}`; } counter.reset = () => count = 0; return counter; }; const counter = makeCounter(); console.log(counter()); console.log(counter()); counter.reset(); console.log(counter()); 

You can also add a reset argument to the function.

function makeCounter() {
    let count = 0;
    return function(reset) {
        if (reset)
            count = 0;
        ++count;
        return `count equals ${count}`;
    };
}

At present, counter is only capable of accepting a single (unnamed) message, whose side effect is to increment the inner state count . In order to add a resetting functionality, you should augment counter so as to accept one more message.

In this respect, a possible approach is to introduce explicit message passing by way of string arguments (see also SICP, Exercise 3.11 in Chapter 3 ):

  function makeCounter() { let count = 0; return function (msg) { switch (msg) { case 'increment': count++; return count; case 'reset': count = 0; break; default: throw new Error('unknown message'); }; }; } let counter = makeCounter(); console.log(counter('increment')); // output: 1 console.log(counter('increment')); // output: 2 counter('reset'); console.log(counter('increment')); // output: 1 

However, at this point we can mechanically replace the explicit dispatching on msg by taking advantage of JavaScript object type, as in:

 function makeCounter() { let count = 0; return { increment: function() { count++; return count; }, reset: function() { count = 0; } }; } let counter = makeCounter(); console.log(counter.increment()); // output: 1 console.log(counter.increment()); // output: 2 counter.reset(); console.log(counter.increment()); // output: 1 

Therefore, a convenient solution might be achieved by having makeCounter return an object such that each message type is associated with the corresponding closure, as per the closures are a poor man's object argument.

Consider passing argument to counter function to reset it to 0:

function makeCounter() {
  let count = 0;
  return function(reset) {
    if (reset === true) {
      count = 0;
    }
    ++count;
    return `count equals ${count}`; 
  };
};

console.log(counter()); // count equals 1
console.log(counter()); // count equals 2
console.log(counter(true)); // count equals 1

You can pass reset count to function as shown below

 function makeCounter() { let count = 0; return function(startCount) { count = startCount ? startCount : ++count; return `count equals ${count}`; }; }; let counter = makeCounter(); // As expected, calling counter again updates it (storing the updated count value) console.log(counter()); // count equals 1 console.log(counter()); // count equals 2 // now counter will reset to value passed console.log(counter(1)); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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