views:

470

answers:

4

I have a JavaScript object that is treated as an associative array. Let's call it "fields". It has several elements, e.g.:

fields['element1'] = ...
fields['element2'] = ...
fields['element3'] = ...

Given fields[0], is it possible to obtain the name of the property (which is "element1") instead of its value?

+3  A: 

No, for two reasons.

  1. fields[0] and fields["element1"] are different properties.
  2. properties in an object are explicitly unordered

You could loop over the properties:

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

…to get the "first" property for some arbitrary value of "first" that could change at any time.

http://ajaxian.com/archives/fun-with-browsers-for-in-loop explains the hasOwnProperty pattern.

David Dorward
It might be worth explaining what `hasOwnProperty` does. It's possible that the OP wants the first of fields, including ones defined in `prototype` (but most likely he wants your method.)
Blixt
A: 

There is no fields[0] (unless fields is an Array object, which supports numerical indices), so you can't get its name just like that. But you can simulate it like this:

function getKey(obj, i) {
    var j = 0;
    for (var p in obj) {
        if (j++ == i) return p;
    }
    return null;
}

for (var p in obj) will loop through every field name in the object obj. By getting the nth field name, you can effectively get the "key" for a certain index.

Note that while it's working its way to become a standard, the order of field names is currently not guaranteed according to the standards, which means that after modifying the object, the same function call could theoretically return a different field name. Same thing goes that different browsers can return different results. Practically, you'll find that just about all the browsers do keep the order of field names so you shouldn't have to worry about it at all.

Blixt
Does the loop iterate in a defined order?
Thilo
See the text I just added to my answer.
Blixt
"Practically, you'll find that just about all the browsers do keep the order of field names". Even if you add more fields?
Thilo
New field names are added to the end of the list as the object is modified.
Blixt
A: 

Just to point out what is implicit in everyone else's answer: "associative arrays" in Javascript are actually just Object instances, e.g.,

var aa = {};
aa.foo = 'argle';
alert(aa['foo']); // Will alert 'argle'

PLEASE don't use an Array instead of an Object—it has the potential to wreak havoc on for key in aa-style iteration.

Hank Gay
Good point. In too many libraries (*commonly used* libraries!) have I seen the mistake of doing `something = []` or `something = new Array()` followed by `something['key'] = 123`. Examples include WMD (the real-time Markdown editor used here on SO) and jQuery UI.
Blixt
A: 

Let's say you have an object oObject. It could be:

var oObject = {} ;
oObject["aaa"] = "AAA" ;
oObject["bbb"] = "BBB" ;
oObject["ccc"] = "CCC" ;
oObject["ddd"] = "DDD" ;
oObject["eee"] = "EEE" ;

Now, let's say you want to know its properties' names and values, to put into the variable strName and strValue. For that you use the "for(x in o)" construct, as in the following example:

var strName, strValue ;

for(strName in oObject)
{
   strValue = oObject[strName] ;
   alert("name : " + strName + " : value : " + strValue) ;
}

The "for(x in o)" construct will iterate over all properties of an object "o", and at each iteration, will put in variable "x" the current property name. All you have to do, then, to have its value, is to write o[x], but you already knew that.

Additional info

After some thinking, and after seeing the comment of Hank Gay, I feel additional info could be interesting.

Let's be naive (and forget the "in JavaScript, all objects, including arrays, are associative containers" thing).

You will usually need two kind of containers: Maps and Arrays.

Maps are created as in my example above (using the "o = new Object() ;" or the "o = {} ;" notation, and must be accessed through their properties. Of course, maps being maps, no ordering is guaranteed.

Arrays are created differently, and even if they can be accessed as maps, they should be accessed only through their indices, to be sure order is maintained.

Point is:

  • If you need a map, use a "new Object()" container
  • If you need an array, une an array, use a "new Array()" container
  • Don't EVER mix the two, and don't EVER access the map through indices, and for arrays, ALWAYS access its data through its indices, because if you don't follow those principles, you won't get what you want.
paercebal
Please note that the other answers are correct in pointing out that the iteration order *is not guaranteed*.
Hank Gay
@Hank Gay : Thanks for your comment. I added this info in my answer.
paercebal