I’m trying to wrap my head around private variables in Javascript, temporary variables, and the GC. However, I can’t quite figure out what would happen in the following situation:
MyClass = function() {
this.myProp = new createjs.Shape();
var tempVar = this.myProp.graphics;
tempVar.rect(0, 0, 10, 100);
tempVar = null;
var isDisposed = false;
this.dispose = function() {
if (isDisposed) return;
isDisposed = true;
}
}
var anInstance = new myClass();
My intention was to have isDisposed represent a private status variable, and tempVar be a use-and-throw variable.
Would tempVar get marked for GC? Would isDisposed be marked for GC too? How is the GC to know when I’m trying to declare a temporary variable meant for disposal, and when I’m trying to have a private variable within the object?
I tried to test the following in Chrome, and it seems as if tempVar never gets GC-ed as long as an instance of myClass exists. So I’m not sure what to believe now. I am incredulous that every single local variable that I create for temporary usage will exist in scope for the lifetime of the object.
Javascript does not have strongly typed objects. By setting
tempVarto null, you’re not declaring that you don’t want to use it any more or marking it for collection as in Java or C#, you’re merely assigning it a (perfectly valid) value. It’s a trap to begin thinking that just because you made tempVar an “instance” of an object, that the variable is in fact an object and can be treated as such for its whole lifetime.Basically, variables are just variables in Javascript. They can contain anything. It’s like VB or VBScript in that regard. Scalars do undergo boxing in many cases (as in
'a|c'.split('|')making the string into a String) but for the most part, forget that. Functions are first-class objects meaning you can assign them to variables, return them from functions, pass them as parameters, and so on.Now, to actually destroy something in Javascript, you either remove all references to it (as in the case of an object) or, in the case of an object’s properties, you can remove them like this:
To expand on that point, the following two code snippets achieve identical results:
Both create a local variable called
abcthat happens to be a function. The first one can be thought of as a shortcut for the second one.However, according to this excellent article on deleting that you brought to my attention, you cannot delete local variables (including functions, which are really also local variables). There are exceptions (if the variable was created using
eval, or it is in Global scope and you’re not using IE <= 8, or you ARE using IE <= 8 and the variable was created in Global scope implicitly as inx = 1which is technically a huge bug), so read the article for full details ondelete, please.Another key thing that may be of use to you is to know that in Javascript only functions have scope (and the
windowin browser implementations or whatever the global scope is in other implementations). Non-function objects and code blocks enclosed in{ }do not have scope (and I say it this way since the prototype ofFunctionisObject, so functions are objects too, but special ones). This means that, for example, considering the following code:This will return
1when executed withx > 0because the scope of variable y is the function, not the block. So in fact it’s wrong and misleading to put thevardeclaration in the block since it is in effect (though perhaps not true practice) hoisted to the function scope.You should read up on closures in javascript (I cannot vouch for the quality of that link). Doing so will probably help. Any time a variable’s function scope is maintained anywhere, then all the function’s private variables are also. The best you can do is set them to
undefined(which is more “nothing” than “null” is in Javascript) which will release any object references they have, but will not truly deallocate the variable to make it available for GC.As for general GCing gotchas, be aware that if a function has a closure over a DOM element, and a DOM element somewhere also references that function, neither will be GCed until the page is unloaded or you break the circular reference. In some–or all?–versions of IE, such a circular reference will cause a memory leak and it will never be GCed until the browser is closed.
To try to answer your questions more directly:
tempVarwill not be marked for GC until the function it is part of has all references released, because it is a local variable, and local variables in Javascript cannot be deleted.isDisposedhas the same qualities astempVar.undefinedwhen done with it, and be at ease–I sincerely doubt you will ever experience a problem. If you are concerned, then declare a local objectvar tmpObj = {tempVar: 'something'};and when done with it you can issue adelete tmpObj.tempVar;. But in my opinion this will needlessly clutter your code.Basically, my suggestion is to understand that in coming from other programming languages, you have preconceived notions about how a programming language ought to work. Some of those notions may have validity in terms of the ideal programming language. However, it is probably best if you relinquish those notions and just embrace, at least for now, how Javascript actually works. Until you are truly experienced enough to confidently violate the advice of those who have gone before you (such as I) then you’re at greater risk of introducing harmful anti-patterns into your Javascript code than you are likely to be correcting any serious deficit in the language. Not having to Dispose() stuff could be really good news–it’s this nasty pervasive task that Javascript simply doesn’t require from you, so you can spend more time writing functionality and less time managing the lifetime of variables. Win!
I hope you take my words as kindly as they are meant. I don’t by any means consider myself a Javascript expert–just that I have some experience and a solid competence in understanding how to use it and what the pitfalls are.
Thanks for listening!