Reputation: 2742
When we have code like:
function a(){
var x =0;
this.add=function(){
alert(x++);
}
}
var test = new a();
test.add(); // alert 0
test.add(); // alert 1
test.add(); // alert 2
How does this work? Doesn't that the value of 'x' in a() should be 'gone' as soon as test = new a() is complete? The stack contains x should also be gone as well, right? Or, does javascript always keep all the stacks ever created in case they will be referenced in future? But that wouldn't be nice, would it...?
Upvotes: 2
Views: 395
Reputation: 1074385
What you're seeing is the effect of a closure. The function being defined within the other function gets access to all of the variables and such in scope where it is — even after the outer function returns. More here, but basically, the variables (and arguments) in the function all exist as properties on an object (called the "variable object") related to that function call. Because the function you've bound to this.add
is defined within that context, it has an enduring reference to that object, preventing the object from being garbage-collected, which means that that function can continue to access those properties (e.g., the variables and arguments to the function).
You normally hear people saying that the function closes over the x
variable, but it's more complex (and interesting) than that. It's the access to the variable object that endures. This has implications. For instance:
function foo() {
var bigarray;
var x;
bigarray = /* create a massive array consuming memory */;
document.getElementById('foo').addEventListener('click', function() {
++x;
alert(x);
});
}
At first glance, we see that the click handler only ever uses x
. So it only has a reference to x
, right?
Wrong, the reference is to the variable object, which contains x
and bigarray
. So bigarray
's contents will stick around as well, even though the function doesn't use them. This isn't a problem (and it's frequently useful), but it emphasizes the underlying mechanism. (And if you really don't need bigarray
's contents within the click handler, you might want to do bigarray = undefined;
before returning from foo
just so the contents are released.)
Upvotes: 4
Reputation: 536399
The word you're looking for is “closure”.
Creating a function
inside another function gives the inner function a (hidden) reference to the local scope in which the outer function was running.
As long as you keep a copy of your test
, that has an explicit reference to the add
function, and that function has an implicit reference to the scope created when calling the a
constructor-function. That scope has an explicit reference to x
, and any other local variables defined in the function. (That includes the this
value and the constructor's arguments
— though you can't access them from inside add
as that function's own this
/arguments
are shadowing them.)
When you let go of test
, the JavaScript interpreter can let go of x
, because there's no way to get a reference back to that variable.
Upvotes: 6