492

I would like to get the keys of a JavaScript object as an array, either in jQuery or pure JavaScript.

Is there a less verbose way than this?

var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [];
for (var key in foo) {
    keys.push(key);
}
dreftymac
  • 31,404
  • 26
  • 119
  • 182
Richard
  • 31,629
  • 29
  • 108
  • 145

8 Answers8

789

Use Object.keys:

var foo = {
  'alpha': 'puffin',
  'beta': 'beagle'
};

var keys = Object.keys(foo);
console.log(keys) // ['alpha', 'beta'] 
// (or maybe some other order, keys are unordered).

This is an ES5 feature. This means it works in all modern browsers but will not work in legacy browsers.

The ES5-shim has a implementation of Object.keys you can steal

Gabriel Wamunyu
  • 734
  • 9
  • 25
Raynos
  • 166,823
  • 56
  • 351
  • 396
62

You can use jQuery's $.map.

var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' },
keys = $.map(foo, function(v, i){
  return i;
});
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • Or `each`, if you're doing something with them. `$.each(foo, function(index, value){/* do something with index */});` – Chris Jan 27 '20 at 18:07
40

Of course, Object.keys() is the best way to get an Object's keys. If it's not available in your environment, it can be trivially shimmed using code such as in your example (except you'd need to take into account your loop will iterate over all properties up the prototype chain, unlike Object.keys()'s behaviour).

However, your example code...

var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [];
for (var key in foo) {
    keys.push(key);
}

jsFiddle.

...could be modified. You can do the assignment right in the variable part.

var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [], i = 0;
for (keys[i++] in foo) {}

jsFiddle.

Of course, this behaviour is different to what Object.keys() actually does (jsFiddle). You could simply use the shim on the MDN documentation.

alex
  • 479,566
  • 201
  • 878
  • 984
  • 9
    I liked this `var keys = [], i = 0; for (keys[i++] in foo) {}` +1 – Jashwant Feb 01 '13 at 12:42
  • I heard that "for in" doesn't guarantee order, do you know if Object.keys does? – Chris Stephens May 13 '13 at 19:06
  • @ChrisStephens Neither guarantee order, even if the keys end up being in an ordered array. – alex May 13 '13 at 23:49
  • 3
    all of these solutions need a `hasOwnProperty()` check, surely? – unsynchronized Jul 13 '14 at 00:38
  • @unsynchronized Yes. That's what my last paragraph refers to. – alex Jul 13 '14 at 23:59
  • @alex, +1 for that ninja code. But is it _valid_ JS? By valid I mean if JLINT would complain about it :D (BTW, I mean the `for (keys[i++] in foo) {}` part) – tfrascaroli Dec 18 '14 at 10:14
  • 1
    @TIMINeutron There's no reason why it shouldn't :) – alex Dec 18 '14 at 22:31
  • That second technique is clever, but particularly unreadable to those who do not know the trick. Not a team-friendly code (so, not something to actually do) IMHO. – Greg Oct 27 '16 at 11:15
  • @Greg I agree with you. – alex Oct 27 '16 at 11:29
  • Some nice person should update this answer, or maybe the accepted one, to make use of `hasOwnProperty`, whatever that is, and then mark all the related comments for deletion. I would, but I found `jQuery.each` to be more useful before I looked into it. – Chris Jan 27 '20 at 18:08
17

In case you're here looking for something to list the keys of an n-depth nested object as a flat array:

const getObjectKeys = (obj, prefix = '') => {
  return Object.entries(obj).reduce((collector, [key, val]) => {
    const newKeys = [ ...collector, prefix ? `${prefix}.${key}` : key ]
    if (Object.prototype.toString.call(val) === '[object Object]') {
      const newPrefix = prefix ? `${prefix}.${key}` : key
      const otherKeys = getObjectKeys(val, newPrefix)
      return [ ...newKeys, ...otherKeys ]
    }
    return newKeys
  }, [])
}

console.log(getObjectKeys({a: 1, b: 2, c: { d: 3, e: { f: 4 }}}))
Cody Moniz
  • 4,845
  • 3
  • 22
  • 20
7

I don't know about less verbose but I was inspired to coerce the following onto one line by the one-liner request, don't know how Pythonic it is though ;)

var keys = (function(o){var ks=[]; for(var k in o) ks.push(k); return ks})(foo);
Dexygen
  • 12,287
  • 13
  • 80
  • 147
  • 3
    Maybe that should be `var enumerableKeysOnThePrototypeChain` ;) – alex May 13 '13 at 23:51
  • 1
    Maybe we're smart enough to know we don't have to worry about hasOwnProperty if the object is created entirely under our purview as opposed to being imported from somewhere else – Dexygen Jan 21 '16 at 17:35
  • not as pythonic as @alex's 2nd answer (`for (keys[i++] in foo) {}`) though, because you're still performing `Array.push()` (not to mention declaring a whole function). A pythonic implementation should rely as much on implicit comprehension as possible, and failing that, using a lambda expression. – cowbert Sep 28 '17 at 21:10
5

Summary

For getting all of the keys of an Object you can use Object.keys(). Object.keys() takes an object as an argument and returns an array of all the keys.

Example:

const object = {
  a: 'string1',
  b: 42,
  c: 34
};

const keys = Object.keys(object)

console.log(keys);

console.log(keys.length) // we can easily access the total amount of properties the object has

In the above example we store an array of keys in the keys const. We then can easily access the amount of properties on the object by checking the length of the keys array.

Getting the values with: Object.values()

The complementary function of Object.keys() is Object.values(). This function takes an object as an argument and returns an array of values. For example:

const object = {
  a: 'random',
  b: 22,
  c: true
};


console.log(Object.values(object));
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
2

Year 2022 and JavaScript still does not have a sound way to work with hashes?

This issues a warning but works:

Object.prototype.keys = function() { return Object.keys(this) }
console.log("Keys of an object: ", { a:1, b:2 }.keys() )

// Keys of an object:  Array [ "a", "b" ]
// WARN: Line 8:1:  Object prototype is read only, properties should not be added  no-extend-native

That said, Extending Built-in Objects is Controversial.

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
0

If you decide to use Underscore.js you better do

var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [];
_.each( foo, function( val, key ) {
    keys.push(key);
});
console.log(keys);
mohammad javad ahmadi
  • 2,031
  • 1
  • 10
  • 27