6

I have the following function makeStopwatch that I am trying to work through to better understand javascript closures:

var makeStopwatch = function() {
  var elapsed = 0;
  var stopwatch = function() {
    return elapsed;
  };
  var increase = function() {
    elapsed++;
  };

  setInterval(increase, 1000);
  return stopwatch;
};

var stopwatch1 = makeStopwatch();
var stopwatch2 = makeStopwatch();

console.log(stopwatch1());
console.log(stopwatch2());

When I console.log the calls to stopwatch1 and stopwatch2 I get 0 returned each time respectively.

As I understand the intended functionality of makeStopwatch the variable elapsed would be 0 if returned by the inner function stopwatch. The inner function increase increments the variable elapsed. Then setInterval calls increase after a delay of 1 second. Finally, stopwatch is returned again this time with the updated value which is expected to be 1.

But this doesn't work because inside makeStopwatch, the inner stopwatch, increase, and setInterval functions are all in independent scopes of one another?

How can I revise this to work as I understand it so that elapsed is incremented and that value is closed over and saved so that when I assign makeStopwatch to variable stopwatch1 and call stopwatch1 the updated value is returned?

8
  • Your code is working. Also, CodeSchool? (I put your code exactly as you have it into the console. Run console.log(stopwatch1()) multiple times.) Commented Jul 11, 2015 at 4:21
  • 2
    The code as posted will always log 0 for both as the console.log will occur within 1 second of the stopwatch being created. Try wrapping the bottom two lines in a setTimeout(console.log(stopwatch1()), 2000); setTimeout(console.log(stopwatch2()), 4000); for example to see that the stopwatches are indeed "running" Commented Jul 11, 2015 at 4:25
  • I guess I'm confused because looking at the body of function increase and how elapsed is incremented, as well as taking into my perception of what a real-world stopwatch does, I expect the console.logs to show that the stopwatch is indeed counting upwards. Commented Jul 11, 2015 at 4:42
  • 1
    in your original code, you are console logging once, right when the stopwatch is created, of course you will get a zero - the value of elapsed is initialised to zero, therefore it's output as zero - after one second, it will be 1, after two seconds it'll be 2 and so on Commented Jul 11, 2015 at 4:55
  • 1
    @phizzy @Jaromanda's code is wrong: it should be setTimeout(function() {console.log(stopwatch1())}, 2000); and the same for stopwatch2. Commented Jul 11, 2015 at 5:36

1 Answer 1

3
var makeStopwatch = function() {
  var elapsed = 0;

  // THIS stopwatch function is referenced later
  var stopwatch = function() {
    return elapsed;
  };

  var increase = function() {
    elapsed++;
  };
  // This setInterval will continue running and calling the increase function.
  // we do not maintain access to it.
  setInterval(increase, 1000);

  // THIS returns the stopwatch function reference earlier.  The only way
  // we can interact with the closure variables are through this function.
  return stopwatch;
};

var stopwatch1 = makeStopwatch();
// This runs the makeStopwatch function.  That function *RETURNS* the
// inner stopwatch function that I emphasized above.

console.log(stopwatch1());
// stopwatch1 is a reference to the inner stopwatch function.  We no longer
// have access to the elapsed variable or the function increase.  However
// the `setInterval` that is calling `increase` is still running.  So every
// 1000ms (1 second) we increment elapsed by 1.

So if were were to put all of the above code into the console, and then call console.log(stopwatch1()) sporadically, it will console.log the number of seconds since we created the stopwatch.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.