2

I have an object and I want to access the first element of that object, so first, I need to get the first key of that object. I have two ways to do it but I'm looking for a better way.

The first is:

var firstKey = Object.keys(myObject)[0];

but Object.keys will return an array of all the keys. So if I want just the first key, this method will be too expensive for my quest (especially if myObject have too many keys).

The second method is:

var firstKey = null;
for(var key in myObject){
    firstKey = key;
    break;
}

this works just fine and it's better than the first one but I think it's hideous (for, break and all that mess just to get the first key).

So

I was wondering if there is a much elegant way to get the first key? Something like:

var firstKey from myObject;

EDIT:

I don't care about the ordering I just want to get whatever the first key is.

EDIT2:

I have an object that holds some informations (lets say, for example, a person's name is a key, his email will be the value). Let's say I have a placeholder where some name and it's email adress are printed. If I press delete, I delete that entry (delete myObject[name];), then I need to fill that placeholder with another name and email (I don't care who anyone will do), so the first (or whatever the first is now) will do.

ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
  • 1
    What do you mean by "first element of that object"? – Harris Jan 27 '17 at 20:39
  • The order of `Object.keys` and `for...in` is implementation dependent. – Oriol Jan 27 '17 at 20:40
  • 3
    There really is no "first" key in an object. E.g. `Object.keys(myObject)[0]` will give you the key that was created first in most browsers, but this is not certain. – Tholle Jan 27 '17 at 20:40
  • As far as I know, `Object.keys(myObject)[0]` is the most common way. There isn't any fancy way of doing it – m_callens Jan 27 '17 at 20:41
  • 2
    Possible duplicate of [Access the first property of an object](http://stackoverflow.com/questions/983267/access-the-first-property-of-an-object) – Tholle Jan 27 '17 at 20:41
  • 1
    @Oriol: The order of `Object.keys` is implementation dependent prior to ES5. After ES5 it is defined in the spec. I know, stupid to have an unordered collection to have order but that's what people asked for. Currently all browsers and node.js support the specified ordering but transcompilers like babel etc. don't support it. – slebetman Jan 27 '17 at 20:42
  • 1
    BTW, even if the ordering of properties in objects are specified you should not depend on it. The specified ordering is: keys that look like integers always come first and are ordered numerically, then all other properties are ordered by insertion order. So, if someone adds a numeric key to your object then you're screwed. – slebetman Jan 27 '17 at 20:44
  • @slebetman [Does ES6 introduce a well-defined order of enumeration for object properties?](http://stackoverflow.com/q/30076219/1529630) No – Oriol Jan 27 '17 at 20:44
  • lets just call the order "random"... – Michael Ritter Jan 27 '17 at 20:46
  • I want just to get any key from the object without using the above methods because one is expensive and the other is hideous. – ibrahim mahrir Jan 27 '17 at 20:49
  • @Oriol: Ah, cool. I wish they'd make the language stronger. The `as if` phrasing has been used to argue for specified ordering for a long time. – slebetman Jan 27 '17 at 20:51
  • @ibrahimmahrir This may sound silly, but what do you mean by "any key"? You simply want a key from an object without caring _at all_ which one it is? What about empty objects? – Harris Jan 27 '17 at 20:53
  • @ibrahimmahrir Actually, since `var` is function scope you can just do `for (var firstKey in myObject) break;` but that's rather hackish and generally won't pass code review (unless you're with a bunch of old-school C programmers) – slebetman Jan 27 '17 at 20:55
  • @HarrisWeinstein check **EDIT2** above. – ibrahim mahrir Jan 27 '17 at 21:03
  • Don't be an idealist. Computers are fast enough for these basic operations. – Ram Jan 27 '17 at 21:19
  • @undefined I'm not an idealist. I was just looking for a better way to do it. Now that I haven't I'm sticking to the second method. – ibrahim mahrir Jan 27 '17 at 21:22
  • Well, I said that because I personally have dedicated many hours for optimizing my code unnecessarily during my career as a developer. That was just a suggestion. – Ram Jan 27 '17 at 21:25

2 Answers2

4

Quoted from MDN's documentation on for...in (I highlight):

The for...in statement iterates over the enumerable properties of an object, in arbitrary order.

And the documentation on Object.keys has:

The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).

So the concept of first key is a fuzzy one. A lot has already been said about property order in JavaScript objects. You might want to go through Does JavaScript Guarantee Object Property Order?

You could consider to use a Map instead of a plain object with (apparently) dynamic properties. A Map also stores key/value pairs, but guarantees that insertion order is maintained.

Here is an example on how you could set some key/value pairs, and then get the first one. Then it deletes the first, and the next one becomes the first:

let mp = new Map().set('x', 1)
                  .set('y', 3)
                  .set('z', 14);

let key = mp.keys().next().value;
console.log('before delete, the first key is: ', key);

mp.delete(key);

key = mp.keys().next().value;
console.log('after delete, the first key is: ', key);

Although the call to keys() may give the impression that it will first generate a list of all keys, this is not true: it returns an iterator, not an array, and only the call to next will actually fetch one.

Community
  • 1
  • 1
trincot
  • 317,000
  • 35
  • 244
  • 286
2

The only approach which won't collect all properties in an array is the for...in one.

You can always move it to a function for better abstraction:

function firstKey(obj) {
  for (var key in obj)
    if (Object.getOwnPropertyDescriptor(obj, key))
      return key;
}
firstKey({a: 1}); // "a"
firstKey({});     // undefined

However, note that it won't be well defined, because for...in and Object.keys use an implementation-dependent order.

It would be better if [[OwnPropertyKeys]] returned an iterator and there was some way to expose it:

Object.getOwnPropertyNamesIterator(obj).next().value; // this does not exist :(
Oriol
  • 274,082
  • 63
  • 437
  • 513