I was reading the "Closures" section on the w3schools JavaScript tutorial and I don't understand how the last example works.
http://www.w3schools.com/js/js_function_closures.asp
The goal is to create a "private" variable counter
that only the add
function can manipulate. Here is the code:
<!DOCTYPE html>
<html>
<body>
<p>Counting with a local variable.</p>
<button type="button" onclick="myFunction()">Count!</button>
<p id="demo">0</p>
<script>
var add = (function outer() {
var counter = 0;
return function inner() {return counter += 1;}
})();
function myFunction(){
document.getElementById("demo").innerHTML = add();
}
</script>
</body>
</html>
I edited the two anonymous functions and named them outer
and inner
so they can be more easily referenced. Here is a link of the code in action:
http://www.w3schools.com/js/tryit.asp?filename=tryjs_function_counter3
So initially the variable add
is assigned to a self-invoking function expression. This would execute the outer
function one time and set the counter
to 0. When the button is clicked, myFunction
is called and this puts the returned value of the add
function, the updated counter
value, inside the p tag. So clicking on the button increments the value of the counter
variable by 1 on every onclick event of the button. I don't understand how the value of the counter
value is affected by the outer
and the inner
functions. This is how I (wrongly) understand it:
When the add
function is called by the myFunction
function (upon an onclick event of the button), first the outer
function would set the counter
variable to 0 by the following statement:
var counter = 0;
Intuitively I would think that the return value of the add
function would invoke the inner
function (especially because I can see this code works) but I don't get how. That is one question I have. If I just accept it then the inner
function would increment the counter
variable by 1. I can see how this makes sense for clicking the button that calls the myFunction
function once. For the second time the button is clicked I don't understand how it doesn't reset. I feel that before the second click the counter
variable is 1 and then on the click the outer
function resets the counter
variable back to 0 with this line again:
var counter = 0;
and then the inner
function is invoked. Since the inner
function is nested in the outer
function, it is in the scope to access the counter
variable and then increases it from 0 back to 1. What am I not understanding about this?
I feel I might not quite understand how the return
statement on a function works but I'm not sure. Is the add
variable just the inner
function only because that is what is returned? And how is it invoked if it is inside a return
statement? I don't get how var counter = 0;
is not executed on every click of the button when myFunction
is invoked.
I thought myFunction
invokes the add
function and that executes outer
function, which executes var counter = 0;
and then the inner
function gets returned and invoked and that increases the counter
variable.
I don't quite get if returning a function would invoke the function either. I also don't know if the creation and assignment of the add
variable had anything to do with how this works. I didn't think so at first but who knows? I don't understand this so anything is possible to me right now.
3 Answers 3
I don't get how var counter = 0; is not executed on every click of the button when myFunction is invoked.
Because the code
var add = (function outer() {
var counter = 0;
return function inner() {return counter += 1;}
})();
only executes once. It returns an immediate function, storing it into the add
variable, which you then assign to something else later (using = Add()
). Notice the ending pair of parentheses? That's what causes the outer function to execute immediately, one time.
When the function in the add
variable is assigned, it returns the inner function. That inner function is what gets executed when myFunction
runs.
The only other thing you need to know is that the inner function has access to the counter
variable in the outer function, due to the closure.
-
Thanks Robert Harvey! That makes a lot more sense now. I wasn't understanding what the add variable actually stored but it is more clear now. Thanks again!drj30026abanba– drj30026abanba12/10/2015 05:43:43Commented Dec 10, 2015 at 5:43
You are confused because you are thinking add is:
var add = (function outer() {
var counter = 0;
return function inner() {return counter += 1;}
})();
but actually add is:
add= function inner() {return counter += 1;}
because this function is what outer self executing function is returning and it is assigned to add.
Outer function is executed only once (when it is returning inner function) and initialized variable "counter" to 0.
Child function can access parent function's variable, and each time we are calling add, it just increment "counter" by 1.
add is holding a reference to the function inner i.e. function returned from outer function.
Closures is when a function remembers is its lexical scope even when invoked from outside that lexical scope.
So inner remembers its scope and thus able to access the counter variable . Thus , its inaccessible outside directly and acts as private. But add or inner can manipulate it.
As soon as you refer add to another type the scope in which counter resides gets garbage collected and gets lost.
I recommend you to read books from kyle simpson www.ydkjs.eu/