davidkomer
davidkomer

Reputation: 3078

Variable scope in dynamic functions?

I'm fairly new to Javascript and wrote the following jQuery code which works:

function updateItems() {
        var now = Math.round((new Date()).getTime() / 1000);

        $(".something").each(function() {

             $(this).html(now.toString());

        });
}

updateItems();

Why does this work? One might think that now would not be accessible from inside the function. I guess I could run some tests to see what happens if I try to modify now from inside the function, if I run another each() right after that, etc. But a basic understanding of how the scope works here and generally in Javascript cases like this would be greatly appreciated.

Also, is this type of function accurately called a "dynamic function" or is there a better name for it?

Upvotes: 0

Views: 107

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074138

This is just a nested function. It has access to the now variable because functions have access to the variables in scope where they're defined (this is actually how globals work as well). It's called a "closure" (it "closes over" the variables in scope where its defined), which sounds obscure, but don't worry — closures are not complicated (disclosure: my blog) once you know a couple of things about how JavaScript works.

The fun thing here is that it closes over the now variable that's specific to that particular call to updateItems, and the reference it has is live (it's not a copy of now as of when the function was created). Each call to updateItems creates a new anonymous function you're passing to each, and each of those functions has access to the now variable created during the call to updateItems. In your case, you're just using it immediately and returning, but what if you kept a reference to the function? What then? The answer is that's fine, it keeps a reference to the now variable it relates to:

function say(msg) {
    var f = function() {
        alert(msg);
    };
    return f; // We return a reference to the function
}
var s1 = say("Hi");
var s2 = say("there");
s1(); // Alerts "Hi" (see below)
s2(); // Alerts "there"

The call to s1 alerts "Hi" because the function created by our call to say still has access to the msg argument we gave to say, even though say has returned. And the same for s2, of course.

And just to prove that it's not a copy as of when the function is created:

function say(msg) {
    // Create the function
    var f = function() {
        alert(msg);
    };

    // Update `msg`
    msg += " (updated)";

    // Return the function
    return f;
}
var s1 = say("Hi");
var s2 = say("there");
s1(); // Alerts "Hi (updated)"
s2(); // Alerts "there (updated)"

See how the function used the updated version of msg, even though the function was created before we updated it. The function has access to the variable itself, not a copy of the variable's value.

Upvotes: 3

F.X.
F.X.

Reputation: 7317

When you use function() { ... }, you create what is technically called a closure. They effectively can capture everything from the enclosing scope.

If you use now in the closure, you would get the value of now when you execute the closure, and (potentially) not the value it had when you created it.

Note that the enclosing scope here is the scope of the outer function, not of the outer block, and you may have to take extra care if you're creating closures in a loop, for instance.

Upvotes: 5

Related Questions