0

As a followup to this question still trying to grok Javascript function anomalies, can someone explain why the following code works?

My text (Javascript Patterns) states:

If you create a new function and assign it to the same variable that already holds another function, you’re overwriting the old function with the new one.

Which would make me assume that in the following code, the variables count and name would be clobbered when the second definition of the function test is created.

Where are the variables count and name living on?

$(document).ready(function() {

    var test = function() {
        var name = 'The Test Function';
        var count = 1;
        console.log(name + ' has been setup');
        test = function() {
            console.log('Number of times ' + name + ' has been called: ' + count);
            count++;
        };
    }
    test();
    test();
    test();
    test();
    test();
});

Output:

alt text

Community
  • 1
  • 1
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047

3 Answers3

7

You are replacing the test function, but you're replacing it with a function that "closes over" (has an enduring reference to) the variables created by the first function call. That's why you see them living on, even though the previous function call has returned. More about closures here, they're a very important part of the language.

Here's a breakdown of what's happening.

  1. You create a function and assign it to test.
  2. You call test.
  3. The JavaScript interpreter sets up an object, called an execution context, for that call to test. An execution context has something called a variable object. This object (which you cannot directly access) has properties for all of the arguments and vars for that call to test.
  4. Your code in test sets things up, including creating a new function and assigning it to the test variable. The new function has an enduring reference to the execution context in which it was created, which means that even though the first call to test returns, the new function still has access (via the variable object) to the variables created for the call.
  5. You call test again (the new one).
  6. It accesses the variables (properties of the variable object) created by the first call.
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • thanks, the book introduced the above example as a "self-definiing function" and a "lazy function definition", but not as a closure, interesting. Also, the link you provided above states that "all javascript functions are closures", also interesting, a terminology jungle. – Edward Tanguay Dec 17 '10 at 14:59
  • @Edward: It's true, all JavaScript functions are closures (they close over the global execution context). In *practice*, of course, we don't really notice much because we're so used to the concept of global variables, and so we only really say "closure" when closing over something *other* than the global execution context. The book *really* should have called out that the function created within the function was a closure, because it's relying on that fact. Even if it didn't want to use the term "closure", it should have highlighted the concept. – T.J. Crowder Dec 17 '10 at 15:10
0

By defining your second test function within the first (where the variables name and count are declared), you are creating a closure which keeps a reference to those variables even though the reference to the old test function is gone.

If you take the second test function out of the first, you will get undefined for name and count.

David Tang
  • 92,262
  • 30
  • 167
  • 149
0

The function hasn't been redefined. A reference to a new function has been assigned to the variable that previously held a reference to the old function.

Since the new function references variables defined in the old function, they don't get deleted by garbage collection.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335