Search code examples
javascriptself-invoking-function

Use of self-Invoking functions in JavaScript closures


I'm currently finishing reading up on JavaScript. I am on the chapter about closures in JavaScript (to allow "private variables"), on http://www.w3schools.com/js/js_function_closures.asp.

The example is a counter:

<!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 () {
    var counter = 0;
    return function () {return counter += 1}
})()

function myFunction(){
    document.getElementById("demo").innerHTML = add();
}
</script>

</body>
</html>

It states that it makes use of a self-invoking function to set the counter to 0 once, and increments counter by one for every iteration of add(). However, I see in the code that the curly braces used to self-invoke a function is around both the counter = 0 and the function to increment counter. It's just difficult for me to visualize how exactly both commands can be inside the self-invoking function but one runs only once, while the other runs every iteration.


Solution

  • Let's break this problem down into pieces :

    (1)

     var add = (function () {
            var counter = 0;
            return function () {return counter += 1;}
        })();
    

    first part is the self invoking anonymous function, this means that add will receive the result of execution of this function. Which in this case is nothing but the following anonymous function :

    function () {return counter += 1;}   (2)
    

    so this means that add will be a function !

    Now the fun part is that inside the siaf (1) (self-invoking-anonymous function), we're declaring a counter variable, initialized to zero :

    var counter = 0;
    

    since counter belongs to the outer scope of (2), then (2) has access to it!

    what JavaScript says, is that a function when created will capture its environment and persist it, so a closure (close over) is nothing but the combination of a function and its creation environment. That means that after return statement the add function which will now hold a reference to (2) will still have access to the counter variable which is initially set to 0;

    so to increment the counter, we need increment (2), which means incrementing add like so :

    add();
    

    p.s : function created with Function constructor and returned in the same way as (2) won't capture the counter variable !!