views:

2058

answers:

5

With a Javascript Array, I can reset it to an empty state with a single assignment:

array.length = 0;

This makes the Array "appear" empty and ready to reuse, and as far as I understand is a single "operation" - that is, constant time.

Is there a similar way to clear a JS Object? I know I can iterate its fields deleting them:

for (prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj.prop; } }

but this has linear complexity.

I can also just throw the object away and create a new one:

obj = {};

But "promiscuous" creation of new objects leads to problems with Garbage Collection on IE6. (As described here)

A: 
delete obj;
obj = { };
nickf
From what I heard about the IE6 garbage collection problem, deleting an object doesn't really help. GC runs every "X" allocations, and takes progressively longer each time, so any code that wants to run in IE6 needs to be very conservative about objects it creates - reuse is key.
levik
It's not really that bad. The main problem with IE6 GC is that it doesn't work when there's a reference cycle containing a non-JScript object (usually a DOM Node). Unless you're creating thousands of these things it's probably not worth worrying about.
bobince
See the link I added to the question body. This is a huge problem for long-lived applications (ones that are open all day such as GMail)
levik
+2  A: 

The short answer to your question, I think, is no (you can just create a new object).

1) In this example, I believe setting the length to 0 still leaves all of the elements for garbage collection.

2) You could add this to Object.prototype if it's something you'd frequently use. Yes it's linear in complexity, but anything that doesn't do garbage collection later will be.

3) This is the best solution. I know it's not related to your question - but for how long do we need to continue supporting IE6? There are many campaigns to discontinue the usage of it.

Feel free to correct me if there's anything incorrect above.

jthompson
Some companies have to support IE6 as a matter of policy - and will while it enjoys double-digit market share. The IE GC issue isn't that things go uncollected, it's that collection runs every X allocations, and takes longer each time. Thus the need to reuse objects.
levik
Yeah, there are many cases where it's still used due to company policy/etc. I was off topic ranking out of spite :)So how does delete obj.prop; perform when the property is itself an object? I don't know if you gain much efficiency there.
jthompson
poor GC means that IE6 will run slower, meaning that there's even more incentive to upgrade. You're still supporting it, it's just that it'll run slow.
nickf
It means your app performs poorly for a portion of your target audience. Some people don't have the option of upgrading because they are in a controlled IT environment. Perhaps their company uses an Active-X control that only works with IE6.
levik
A: 

If yu want to keep obj and lose its instance properties: obj=new obj;

for instance:

function obj(args){
    args= args || {};
    for(var p in args) this[p]= args[p];
}

obj.prototype.countproperties= function(){
    for(var p in this){
     if(this.hasOwnProperty(p)) count++;
    }
    return count;
}

If you have an obj object, you can 'empty' it with obj=new obj;

Calling obj.countproperties() will return 0, instead of an error.

kennebec
That's the same as obj = {};
levik
not if obj is a constructor
kennebec
if obj is a constructor, then it should be obj=new obj();
Martijn
Maybe you mean obj=new Object(); which is a default empty object.
Thevs
A: 

The best way to clean up objects is to define them in some quite a tight scope (and not in any kind of closures!), Then, when you leave that scope, it automatically gets GC'ed.

If f.e. you create it within a function (or method), it gets destroyed every time you return from a function (except for the case when external references to it had been created, then it becomes closured, pls. be aware). It is possible to take advantage of this when you design your code.

For more details you can read JS manuals what the scope for objects is about, and how it is determined.

For the case obj = {}, the object becomes empty, but previous content becomes anonymous, and may not always be GC'ed (depending on presence of foreign references).

Thevs
A: 

So to recap your question: you want to avoid, as much as possible, trouble with the IE6 GC bug. That bug has two causes:

  1. Garbage Collection occurs once every so many allocations; therefore, the more allocations you make, the oftener GC will run;
  2. The more objects you've got ‘in the air’, the more time each Garbage Collection run takes (since it'll crawl through the entire list of objects to see which are marked as garbage).

The solution to cause 1 seems to be: keep the number of allocations down; assign new objects and strings as little as possible.

The solution to cause 2 seems to be: keep the number of 'live' objects down; delete your strings and objects as soon as you don't need them anymore, and create them afresh when necessary.

To a certain extent, these solutions are contradictory: to keep the number of objects in memory low will entail more allocations and de-allocations. Conversely, constantly reusing the same objects could mean keeping more objects in memory than strictly necessary.


Now for your question. Whether you'll reset an object by creating a new one, or by deleting all its properties: that will depend on what you want to do with it afterwards.

You’ll probably want to assign new properties to it:

  • If you do so immediately, then I suggest assigning the new properties straightaway, and skip deleting or clearing first. (Make sure that all properties are either overwritten or deleted, though!)
  • If the object won't be used immediately, but will be repopulated at some later stage, then I suggest deleting it or assigning it null, and create a new one later on.

There's no fast, easy to use way to clear a JScript object for reuse as if it were a new object — without creating a new one. Which means the short answer to your question is ‘No’, like jthompson says.

Martijn