203

I know in JavaScript, objects double as hashes, but I have been unable to find a built-in function to get the keys:

var h = {a:'b', c:'d'};

I want something like

var k = h.keys() ; // k = ['a', 'c'];

It is simple to write a function myself to iterate over the items and add the keys to an array that I return, but is there a standard cleaner way to do that?

I keep feeling it must be a simple built in function that I missed but I can't find it!

Pat
  • 36,282
  • 18
  • 72
  • 87

10 Answers10

289

There is function in modern JavaScript (ECMAScript 5) called Object.keys performing this operation:

var obj = { "a" : 1, "b" : 2, "c" : 3};
alert(Object.keys(obj)); // will output ["a", "b", "c"]

Compatibility details can be found here.

On the Mozilla site there is also a snippet for backward compatibility:

if(!Object.keys) Object.keys = function(o){
   if (o !== Object(o))
      throw new TypeError('Object.keys called on non-object');
   var ret=[],p;
   for(p in o) if(Object.prototype.hasOwnProperty.call(o,p)) ret.push(p);
   return ret;
}
Jost
  • 199
  • 1
  • 3
  • 16
Ivan Nevostruev
  • 28,143
  • 8
  • 66
  • 82
  • wouldn't this have been more natural? `if(!Object.prototype.keys) Object.prototype.keys = function() { if (this !== Object(this)) throw new TypeError('Object.keys called on non-object'); var ret = [], p; for (p in this) if (Object.prototype.hasOwnProperty.call(this, p)) ret.push(p); return ret; } var x = { a: { A: 1, B: 2, C: 3 }, b: { A: 10, B: 20 } }; alert(x.a.keys());` – ekkis Dec 22 '11 at 00:44
  • 2
    As I understand this `Object.prototype.keys` will make `keys` available to all sub-classes of Object, therefore for all objects. Which probably you want to if you're trying to use OOP. Anyway this really depends on your requirements. – Ivan Nevostruev Dec 22 '11 at 21:12
  • 1
    If you use mootools, Object.keys() should be available in all browsers. – thepeer Sep 10 '12 at 16:43
  • Is there anything to use this in angular templates? Its not working there inside partials. – Jay Shukla Dec 06 '13 at 14:52
  • I think you should ask this as separate question with code sample. – Ivan Nevostruev Dec 07 '13 at 01:05
82

For production code requiring a large compatibility with client browsers I still suggest Ivan Nevostruev's answer with shim to ensure Object.keys in older browsers. However, it's possible to get the exact functionality requested using ECMA's new defineProperty feature.

As of ECMAScript 5 - Object.defineProperty

As of ECMA5 you can use Object.defineProperty() to define non-enumerable properties. The current compatibility still has much to be desired, but this should eventually become usable in all browsers. (Specifically note the current incompatibility with IE8!)

Object.defineProperty(Object.prototype, 'keys', {
  value: function keys() {
    var keys = [];
    for(var i in this) if (this.hasOwnProperty(i)) {
      keys.push(i);
    }
    return keys;
  },
  enumerable: false
});

var o = {
    'a': 1,
    'b': 2
}

for (var k in o) {
    console.log(k, o[k])
}

console.log(o.keys())

# OUTPUT
# > a 1
# > b 2
# > ["a", "b"]

However, since ECMA5 already added Object.keys you might as well use:

Object.defineProperty(Object.prototype, 'keys', {
  value: function keys() {
    return Object.keys(this);
  },
  enumerable: false
});

Original answer

Object.prototype.keys = function ()
{
  var keys = [];
  for(var i in this) if (this.hasOwnProperty(i))
  {
    keys.push(i);
  }
  return keys;
}

Edit: Since this answer has been around for a while I'll leave the above untouched. Anyone reading this should also read Ivan Nevostruev's answer below.

There's no way of making prototype functions non-enumerable which leads to them always turning up in for-in loops that don't use hasOwnProperty. I still think this answer would be ideal if extending the prototype of Object wasn't so messy.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AnnanFay
  • 9,573
  • 15
  • 63
  • 86
  • 9
    'hasOwnProperty' excludes properties on the prototypes of this object, which is useful to know. – ijw Nov 13 '09 at 11:09
  • 2
    Answer accepted because that's how I ended up implementing it but I feel this should have been a built-in function of the language. – Pat Mar 29 '11 at 22:16
  • 5
    Note that you should use "for (var i in this)..." to avoid creating a global variable. – Brad G. May 13 '11 at 12:31
  • 5
    I'd avoid modifying Object.prototype - as another commenter noted below, this can easily break scripts which aren't careful about checking hasOwnProperty(). Instead, use the less OO-friendly way: define a 'keys' function if it doesn't already exist. (Firefox and Chrome both implement a native keys() function which does exactly what the OP wants - IE does not) – digitalbath May 31 '11 at 22:08
  • There isn't a `Object.prototype.keys` in ECMAScript 5. https://gist.github.com/1034464 – rxgx Aug 11 '11 at 18:35
  • 1
    It seems to be a bad idea to add anything to Object.prototype, as it breaks every normal loop like: for (var k in array) { } or for (var k in object), and that idiom - though it might be faulty - is extremely common. For example according to Matthew Darwin's answer below, it breaks Google Maps. – Sam Watkins May 07 '12 at 08:01
  • This is not the way to go for a number of reasons; 1) You really shouldn't be adding things to `Object.prototype` at all, and certainly not this way 2) You should be using `Object.keys` as mentioned in Ivan Nevostuev's answer – Oliver Nightingale Sep 03 '12 at 14:32
  • @OliverNightingale I'm not sure how to take your comment. I already say the same thing in the *Edit* part of my answer. – AnnanFay Sep 10 '12 at 12:15
45

You can use Object.keys:

Object.keys(h)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Leticia Santos
  • 549
  • 5
  • 7
33

You could use Underscore.js, which is a JavaScript utility library.

_.keys({one : 1, two : 2, three : 3});
// => ["one", "two", "three"]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
timotti
  • 339
  • 3
  • 2
  • Well, it's not really what was asked, because @Pat is looking for a built-in function, but it's an interesting library nonetheless, and it does not modify `Object.prototype` – fresskoma Aug 11 '11 at 22:11
  • 2
    These days, I think it is much more helpful to use these nifty little library-lets than go on writing your own implementations... Anyways, in most real-world projects, we are anyways using Underscore or equivalent libraries. Personally, I'd rather go with Underscore. – kumarharsh Aug 22 '12 at 20:40
  • `_.keys(obj).length` to see if there are any keys. – chovy Sep 24 '12 at 21:04
14

This is the best you can do, as far as I know...

var keys = [];
for (var k in h)keys.push(k);
danb
  • 10,239
  • 14
  • 60
  • 76
  • 2
    This also doesn't work when Object.prototype has been messed with. – Phil Jul 26 '11 at 08:40
  • 4
    It would be better to use this, and not to "mess with" Object.prototype. It seems that everything breaks if we add things to Object.prototype: it is an extremely common idiom to loop over the keys of an array / object. – Sam Watkins May 07 '12 at 07:59
8

Using jQuery, you can get the keys like this:

var bobject =  {primary:"red", bg:"maroon", hilite:"green"};
var keys = [];
$.each(bobject, function(key, val){ keys.push(key); });
console.log(keys); // ["primary", "bg", "hilite"]

Or:

var bobject =  {primary:"red", bg:"maroon", hilite:"green"};
$.map(bobject, function(v, k){return k;});

Thanks to @pimlottc.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
chim
  • 8,407
  • 3
  • 52
  • 60
  • 3
    If you wanted to go this route, you might as well use `JQuery.map`: `$.map(h, function(v,k) { return k; });` – pimlottc May 16 '12 at 14:20
6

I believe you can loop through the properties of the object using for/in, so you could do something like this:

function getKeys(h) {
  Array keys = new Array();
  for (var key in h)
    keys.push(key);
  return keys;
}
palmsey
  • 5,812
  • 3
  • 37
  • 41
4

I wanted to use AnnanFay's answer:

Object.prototype.keys = function () ...

However, when using it in conjunction with the Google Maps API v3, Google Maps is non-functional.

However,

for (var key in h) ...

works well.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

In Javascript we can use

Object.keys(h)
Mouzam Ali
  • 27
  • 3
1

If you are trying to get the elements only, but not the functions then this code can help you:

this.getKeys = function() {

    var keys = new Array();
    for (var key in this) {

        if (typeof this[key] !== 'function') {

            keys.push(key);
        }
    }
    return keys;
}

This is part of my implementation of the HashMap and I only want the keys. this is the hashmap object that contains the keys.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zeacuss
  • 2,563
  • 2
  • 28
  • 32