views:

1340

answers:

5

Is there a way to get (from somewhere) the number of elements in a javascript object?? (i.e. constant-time complexity).

I cant find a property or method that retrieve that information. So far I can only think of doing an iteration through the whole collection, but that's linear time.
It's strange there is no direct access to the size of the object, dont you think.

EDIT:
I'm talking about the Object object (not objects in general):

var obj = new Object ;
+2  A: 

The concept of number/length/dimensionality doesn't really make sense for an Object, and needing it suggests you really want an Array to me.

Edit: Pointed out to me that you want an O(1) for this. To the best of my knowledge no such way exists I'm afraid.

annakata
it occurs to me jQuery probably has a way to do this...
annakata
He proposed iterating himself, which this solution is. He needed an O(1) way to achieve this...
Thomas Hansen
You're quite right. Really should read questions more thoroughly.
annakata
A: 

AFAIK, there is no way to do this reliably, unless you switch to an array. Which honestly, doesn't seem strange - it's seems pretty straight forward to me that arrays are countable, and objects aren't.

Probably the closest you'll get is something like this

// Monkey patching on purpose to make a point
Object.prototype.length = function()
{
  var i = 0;
  for ( var p in this ) i++;
  return i;
}

alert( {foo:"bar", bar: "baz"}.length() ); // alerts 3

But this creates problems, or at least questions. All user-created properties are counted, including the _length function itself! And while in this simple example you could avoid it by just using a normal function, that doesn't mean you can stop other scripts from doing this. so what do you do? Ignore function properties?

Object.prototype.length = function()
{
  var i = 0;
  for ( var p in this )
  {
      if ( 'function' == typeof this[p] ) continue;
      i++;
  }
  return i;
}

alert( {foo:"bar", bar: "baz"}.length() ); // alerts 2

In the end, I think you should probably ditch the idea of making your objects countable and figure out another way to do whatever it is you're doing.

Peter Bailey
DANGER WILL ROBINSON! Do *NOT* proto against Object! Everything descends from Object, you'll cripple the client processing like this if you're doing any sizeable amount of JS work.
annakata
Uh... did you not read the part where I wrote in a comment "Monkey patching on purpose to make a point" - c'mon, I did that deliberately so that people wouldn't flip a bit about it. Besides, even though I don't advocate monkey patching, you misunderstand how the prototype chain works in Javascript if you think this would cause performance issues http://video.yahoo.com/watch/111585/1027823
Peter Bailey
+9  A: 

Although JS implementations might keep track of such a value internally, there's no standard way to get it.

On Mozilla-browsers, you can use the non-standard __count__, but for cross-browser scripting you're stuck with explicitly iterating over the properties and checking hasOwnProperty():

function countProperties(obj) {
    var count = 0;

    for(var prop in obj) {
     if(obj.hasOwnProperty(prop))
      ++count;
    }

    return count;
}

Keep in mind that you'll also miss properties which arent enumerable (eg an array's length).

If you're using a framework like jQuery, Prototype, Mootools, $whatever-the-newest-hype, check if they come with their own collections API, which might be a better solution to your problem than using native JS objects.

Christoph
Goddamn it I always forget hasOwnProperty. Too much time in .NET land I tell you. +1
annakata
jQuery uses an object for its collections that it gets from queries, and it exposes that value with a length property.
Nosredna
Works great, thanks for your post! +1
Justin Ethier
A: 
function count(){
    var c= 0;
    for(var p in this) if(this.hasOwnProperty(p))++c;
    return c;
}

var O={a: 1, b: 2, c: 3};

count.call(O);
kennebec
+1  A: 

You can use:

({ foo:55, bar:99 }).__count__ // is: 2

has been taken from here

Artem Barger
This looks like an FF-only property.
EndangeredMassa
In reference stated its JavaScript 1.8 feature.
Artem Barger