0

When making a a variable local to a function, every time the function is called the array is reallocated and 10 things are stuffed into it. In a more complicated situation this can take up time.

This closure apparently solves that problem by returning a function. The function it returns is assigned to digit name and the function is invoked immediately. I cannot wrap my mind around this. Now I somewhat understand what a closure is, but I have no idea how it is working.

var digit_names = (function() {
    var names = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

    return function (n) {
      return names[n];
  };
}());

alert(digit_names(3)); // 'three'

Please explain in detail what is going on here. How is the returned function being invoked before the array is allocated? When I call the function, how is it ignoring var names before it gets to the returned function? Or is that question even accurate?

Michael Rader
  • 5,839
  • 8
  • 33
  • 43

4 Answers4

2

The closure is capturing a reference to the local array names once and keeps it in scope. The local array names is created only and exactly at the point when the outer (anonymous) function is called, not when the returned function is called.

Whenever the returned function is invoked, this same local array is accessed, so there is no re-creation of the array. Thus, this would have similar performance behavior to caching the array and reusing it, instead of re-allocating it every time a function is called.

Note that the returned function is not invoked inside the outer function. It is only defined there.

Update: It appears that the OP is confused about which function the name digit_names refers to. The name digit_names refers to the function which is returned by the outer function, not the outer function itself.

The outer function, which was never given a name, is creating the array names when it is invoked. The outer function then gives birth to the inner function, which captures a reference to names. The outer function then returns the inner function, which gets the assigned to the variable digit_names.

Thus, when that inner (returned) function is invoked as in digit_names(3), it is directly accessing a member of the array that was created by the outer function, which never had a name.

Note that nothing is created when digit_names is called. All the creation happens in the anonymous function that gave birth to digit_names.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • If the inside function is only defined in there... when the alert calls the function it sees the variable and allocates it (I WOULD THINK)... how is the inner function being called without first creating the array?? – Michael Rader May 19 '14 at 21:27
  • @MichaelRadar Array is created when outer function is called. The reference inside the inner function keeps it in scope. – merlin2011 May 19 '14 at 21:29
  • Okay, so when I call the function, `digit_names`, the array is being created and then the value gets returned with the inner function that returns it. I get that. I think. But when you call the function again, how is the function not looking at the variable again and re-creating it before it returns the function?? – Michael Rader May 19 '14 at 21:36
  • @MichaelRader, I understand your source of confusion now. – merlin2011 May 19 '14 at 21:38
  • @MichaelRader, The function `digit_names` is *not* a reference to the outer function. It is a reference to the *inner* function, which the outer, anonymous function *returns*. – merlin2011 May 19 '14 at 21:38
  • @MichaelRader, I just updated the answer. If you prefer an answer with more code, take a look at KevinB's answer. – merlin2011 May 19 '14 at 21:46
  • `digit_names` is not a reference to what outer function? I mean the alert is referencing the `digit_names` function by calling it. I'm sorry but I'm still not understanding. Maybe there's some underlying information I'm getting wrong. – Michael Rader May 19 '14 at 21:49
  • 1
    @MichaelRader, Observe that the `function` keyword is used **twice** in your example. The first time it is used, the *outer function* is defined. The second time it is used, the *inner function* is defined. – merlin2011 May 19 '14 at 21:51
1

I'll start by going over what your code does, then further explain what makes it a closure.

var digit_names = (function() {
    var names = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

    return function (n) {
      return names[n];
  };
}());

alert(digit_names(3)); // 'three'

To begin with, you have an Immediately Invoked Function Expression (iife):

var digit_names = (function () {...}());

What this does is it defines a function, and then immediately executes (or, invokes) it. In your case, the function is:

function() {
    var names = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

    return function (n) {
        return names[n];
    };
}

What this function does is it first defines a names variable that contains an array, then it returns an anonymous function that will return a single element from that array when executed.

Now lets go back to your original code.

var digit_names = (function() {
    var names = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

    return function (n) {
      return names[n];
  };
}());

alert(digit_names(3)); // 'three'

digit_names is defined as containing the return value of the iife. that means, digit_names contains this function:

function (n) {
    return names[n];
}

Since that function was defined inside the iife, it has access to all variables defined within the iife, making names defined as the array. The fact that the function references the names array is what makes it a closure.

digit_names contains the return value of the iife which is a function that returns a value from the names array. By referencing the names array, that function can be called a closure. Put another way, digit_names references a function that references a variable that was defined within the same scope that the function was defined in.


Here's another example:

var names = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
var digit_names = function (n) {
    return names[n];
}
alert(digit_names(3)); // 'three'

In this case, digit_names still stores a reference to the anonymous function, and the anonymous function is still a closure, however the names array is no longer private. The end result is the same though, because names is only created once.

Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • Thank you so much. What I didn't understand was IIF. I was looking at this as a regular function being called, but this is actually a function stored in a variable. What I'm still not understanding (if you can please include it) is what is the additional `()` for at the end of the IIF, `}());` – Michael Rader May 19 '14 at 22:02
  • 1
    without the `()`, it would just be an FE (function expression). By adding `()` at the end, it gets immediately executed (or "invoked") making it an IIFE. So, instead of storing that function in `digit_names`, you're storing the returned value of it, in this case, an anonymous function that references `names` – Kevin B May 19 '14 at 22:03
  • note that nothing is truly *private* in javascript. – Kevin B May 19 '14 at 22:13
0

In your example above, you have an immediately invoked function that creates the {{names}} array once and then returns another function that references the array. The closure closes around the names array and ensures that the array never gets garbage collected as long as there is a reference to the function that contains it.

Your example is semantically equivalent to:

function closure() {
    var names = ['zero', 'one', 'zero', 'one', 'zero', 'one', 'zero', 'one', 'zero', 'one'];

    return function (n) {
      return names[n];
  };
}

var digit_names = closure();

{{closure}} is only invoked once and the function that is returned is assigned to {{digit_names}}. {{digit_names}} contains a reference to the {{names}} variable from {{closure}}.

Because you only need to create {{names}} once, you save allocation time.

Andrew Eisenberg
  • 28,387
  • 9
  • 92
  • 148
  • I don't understand how the 'names' variable is closed with a closure? It looks the same to me as any of other function. – Michael Rader May 19 '14 at 21:17
  • But you do understand the concept, right? are we just dealing with a terminology issue now? a closure is a function, but not all functions are closures. the `closure` function in andrew's example is not a closure, the function that it returns is a closure. The function that it returns references, or, *wraps*, the names array such that it will stay in scope for that function to reference regardless of where the function is executed. As long as a reference to that function is stored somewhere, the names array will exist for it to access. – Kevin B May 19 '14 at 21:23
  • @KevinB no this isn't about terminology. I'm just not understanding still! You say that as long as their is a reference to that function then the array will exist. By calling the function (without returning it from within the function) it is still being referenced, no?? – Michael Rader May 19 '14 at 21:31
0

Think of the closure as an amoeba. It takes locally defined variables like 'names' and gelatinously closes in around them. It then takes a reference to the 'names' array wherever it goes, and it does not to redefine it every time it gets called.

CodeOwl
  • 662
  • 2
  • 9
  • 23