0

I'm looking at a JavaScript exercise and the output's a little confusing.

In the code below each time 'counter' is called the value of 'i' outputted to the console increases, but in the constructor 'i' is reset to '0' at the beginning of the object's code, so should really return '1' each time 'counter' is called.

Why is 'i' not being reset to '0' each time 'counter' is called?

Thanks in advance!:)

function makeCounter() {

   var i = 0;

   return function() {
     console.log( ++i );
   };
}

var counter = makeCounter();
counter(); //Output is 1.
counter(); //Output is 2.
counter(); //Output is 3...
  • 2
    Possible duplicate of [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Andreas Jan 22 '18 at 10:34

4 Answers4

4

Remember: calling counter() doesn't call makeCounter(). It calls the function that makeCounter returns. Because the returned function doesn't reset i's value, i never gets reset.

i is only set to 0 when makeCounter is called. As that code shows, makeCounter is only called once.

EKW
  • 2,059
  • 14
  • 24
  • Hi @EKW, thanks for you reply. It makes sense now you mention it that 'var i = 0' is only executed once, when the constructor makeCounter is called, but is 'i's value not changed because a method hasn't mutated it? Or put another way, after the constructor has done its work and set up the memory space for 'i', the assignment statement var is ignored going forwards? Can properties in an object only be mutated by the object's method calls? Hope this makes sense??!!:) – TheLemonSong Jan 22 '18 at 11:19
  • @TheLemonSong It isn't being ignored. It never gets executed because it is never told to execute that part again. Remember, `counter()` doesn't call `makeCounter()`. Calling `counter()` just does `console.log(++i)`. – EKW Jan 22 '18 at 11:24
  • or is the statement 'var i = 0;' ignored when the object 'counter' is called because 'i' already exists in the instance and the JS engine is smart enough to understand this? – TheLemonSong Jan 22 '18 at 11:24
  • It is not ignored. Counter doesn't include `var i = 0` because that that's not contained inside the function. It is not ignored because counter doesn't include that line in the first place. Counter is the function that is returned from makeCounter. makeCounter has `var i = 0` in it but `counter` doesn't because... well look at the returned function. It just doesn't. – EKW Jan 22 '18 at 11:28
  • you beat me to the punch;) So when 'counter' is directly called, rather than say accessed via a method, the only thing that is returned is whatever is explicitly returned or the whole object if nothing is nothing explicitly is stated to be returned? It's just a call to an object, the object returns either itself or whatever it is told internally to return? – TheLemonSong Jan 22 '18 at 11:30
  • @TheLemonSong counter is defined here: `return function() { console.log( ++i ); };`. You see how it doesn't contain `var i = 0;` inside of it anywhere? – EKW Jan 22 '18 at 11:30
  • If a function doesn't return anything, it just returns undefined. Regardless of where you call counter, the result will be the same, as `counter` never ever resets the value of `i`. There are no objects involved in this. – EKW Jan 22 '18 at 11:32
  • I think the penny dropped when you said 'Counter is the function that is returned from makeCounter. ', or put another way, properties and methods are created by the constructor makeCounter and stored as the object counter. 'var i = 0;' is code executed by the constructor to create the property 'i', the line 'var i = 0;' isn't ignored by 'counter' because it doesn't know it exists. Does that make sense? – TheLemonSong Jan 22 '18 at 11:42
  • Yea, that sounds about right. If my answer helped you, feel free to mark it as correct :) – EKW Jan 22 '18 at 11:45
  • Excellent, I learned something! Thanks for your time and help and sharing your knowledge with me EKW:) – TheLemonSong Jan 22 '18 at 11:51
4

i is not changed every time because you are not updating the i is is accessed via closures so the first function is called only once

to update it do like this

function makeCounter() {

   return function() {
     var i = 0;
     console.log( ++i );
   };
}

var counter = makeCounter();
counter(); //Output is 1.
counter(); //Output is 1.
EKW
  • 2,059
  • 14
  • 24
zabusa
  • 2,520
  • 21
  • 25
  • Hi @zabusa. Thanks for taking the time to look at this question:) Would 'i' be accessed via closures as 'counter' is an named object, so should just sit in memory with all its properties? If 'counter' was an object being passed around it would use a closure containing everything that is referenced by the code until nothing references it, and then get GC'd? – TheLemonSong Jan 22 '18 at 11:49
2

you are calling the same counter which have the same i variable, it shouldn't be reset because it will call var i = 0; only the time you instantiate the counter then it will keep calling ++i to increase it, if you want new value for it call a new counter :

function makeCounter() {
   var i = 0;
   return function() {
     console.log( ++i );
   };
}
var counter = makeCounter();
counter(); //Output is 1.
counter(); //Output is 2.
counter(); //Output is 3...
var second = makeCounter();
second(); //Output is 1.
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Ashar Dweedar
  • 613
  • 6
  • 16
0

If you want to reset the counter you have to call makeCounter() again as it only returns the function that you access with counter. It is the concept of closure that only remembers the returned function.

mosabbir tuhin
  • 560
  • 4
  • 14