65

I cannot find the JavaScript equivalent of PHP array_keys() / array_values().

For people unfamiliar with PHP given the following JavaScript hash:

var myHash = {"apples": 3, "oranges": 4, "bananas": 42}

How can I get an array of keys, i.e.,

["apples", "oranges", "bananas"]

The same question with the values, i.e.,

[3, 4, 42]

jQuery can be used.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
greg0ire
  • 22,714
  • 16
  • 72
  • 101
  • possible duplicate of [Get array of object's keys](http://stackoverflow.com/questions/8763125/get-array-of-objects-keys) and [How to get all properties values of a Javascript Object (without knowing the keys)?](http://stackoverflow.com/questions/7306669/how-to-get-all-properties-values-of-a-javascript-object-without-knowing-the-key). – Felix Kling May 02 '12 at 13:56

9 Answers9

87

In ES5 supported (or shimmed) browsers...

var keys = Object.keys(myHash);

var values = keys.map(function(v) { return myHash[v]; });

Shims from MDN...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • @greg0ire: Supported browsers are generally any modern browser. Generally most Chrome and Safari in use, Firefox 4+, Opera 10+ *(maybe earlier?)*, and IE9. You can easily shim both of these methods to support legacy browsers. –  May 02 '12 at 14:00
  • @greg0ire: I added links to the shims provided by MDN. –  May 02 '12 at 14:07
  • Very good solution, but the code should be compatible with IE7-8 if possible. – greg0ire May 02 '12 at 14:08
  • @greg0ire: Including the linked shims will make it compatible, but if you don't want those, then IE7/8 won't work. –  May 02 '12 at 14:13
  • This also works: `var values = keys.map(key=>myHash[key]);` – Dmitry Kozlov May 03 '19 at 14:16
  • 5
    `var values = Object.values(myHash);` per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values – konyak May 16 '19 at 17:36
53
var a = {"apples": 3, "oranges": 4, "bananas": 42};    

var array_keys = new Array();
var array_values = new Array();

for (var key in a) {
    array_keys.push(key);
    array_values.push(a[key]);
}

alert(array_keys);
alert(array_values);
Imp
  • 8,409
  • 1
  • 25
  • 36
  • 9
    +1, However the inside of the `for` loop should be wrapped in a check that the current key is actually the Object in question's own property (as opposed to an inherited property). Else, in IE, you can get some unexpected keys: `if (Object.prototype.hasOwnProperty.call(a, key)) {array_keys.push(key);array_values.push(a[key]);}` – JAAulde May 02 '12 at 13:55
  • @JAAulde: I don't know of any such IE issue. when enumerating an object. Could you give a further description of that issue? What keys will be found? –  May 02 '12 at 13:58
  • @amnotiam Crockford recommends it in his LINT instructions at http://www.JSLint.com/lint.html#forin and references an article he wrote on the matter at http://yuiblog.com/blog/2006/09/26/for-in-intrigue/ – JAAulde May 02 '12 at 14:01
  • @JAAulde The members in `Object.prototype` should be marked as non-enumerable and skipped by the "foreach", but yes, I believe older IE could actually have problem with this. Thx. – Imp May 02 '12 at 14:02
  • @JAAulde: To be honest, I don't really care what Crockford recommends. There isn't an IE issue that I'm aware of. The only issue is with adding enumerable properties to `Object.prototype`, which is easily solvable/reversable. –  May 02 '12 at 14:03
  • @Imp Yes, they _should_ be, but as you say versions of IE have issues with it. IIRC, I have had issues with it through IE8, though it may have only been up to 7. – JAAulde May 02 '12 at 14:03
  • @amnotiam I don't recommend because Crockford does, I recommend it because it has bit me in the ass numerous times. I link to Crockford because he does a good job of explaining it. Ignore the advice if you want, it's no matter to me. Just speaking from a lot of experience. – JAAulde May 02 '12 at 14:04
  • @JAAulde: Please then tell me what properties will be encountered in IE from enumerating an object created from literal notation? –  May 02 '12 at 14:05
  • @amnotiam You are correct, it doesn't happen (in my experience) when using literal notation. I am recommending a best coding practice to avoid the need to think about what kind of object you're iterating and to avoid code maint issues should the code in question ever have to iterate something different. – JAAulde May 02 '12 at 14:07
  • @JAAulde: Yeah, that's why I don't like a lot of Crockford's recommendations. Some of them are centered around avoiding the need to think about what one is doing. There certainly are issues with using `for-in` against things like NodeLists, but proper iteration using `for` is the solution, not burdening your code with a test of every property, just so we don't need to think about what we're doing. –  May 02 '12 at 14:12
  • @amnotiam Yeah, to each their own. I consider it a future proofing rather than an "unencumbering of the thought process" (to paraphrase Click and Clack). S'All good. – JAAulde May 02 '12 at 14:19
  • I had to use `for (var key in Object.keys(a)) {` – jcalfee314 Jan 19 '15 at 20:07
15

The second answer (at the time of writing) gives:

var values = keys.map(function(v) { return myHash[v]; });

But I prefer using jQuery's own $.map:

var values = $.map(myHash, function(v) { return v; });

Since jQuery takes care of cross-browser compatibility. Plus it's shorter :)

At any rate, I always try to be as functional as possible. One-liners are nicers than loops.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Literal
  • 757
  • 6
  • 16
13

Look at the _.keys() and _.values() functions in either Lodash or Underscore.js:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Josh Petitt
  • 9,371
  • 12
  • 56
  • 104
4
function getKeys(obj){
    var keys = [];
    for (key in obj) {
        if (obj.hasOwnProperty(key)) { keys[keys.length] = key; }
    } 
    return keys;
}
Abid
  • 7,149
  • 9
  • 44
  • 51
2

I don't know if it helps, but the "foreach" goes through all the keys:

for (var key in obj1) {...}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Igor Deruga
  • 1,504
  • 1
  • 10
  • 18
  • 1
    Watch out for "jquery/prototype"-style objects: these libraries add different functions to all the objects which are being iterated through as if they were keys too... In this case you want to use the Object.each() function provided by the given library: http://api.jquery.com/jQuery.each/ A little off topic, but somewhat important... – Igor Deruga May 02 '12 at 18:51
1

Here are implementations from phpjs.org:

This is not my code. I'm just pointing you to a useful resource.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Surreal Dreams
  • 26,055
  • 3
  • 46
  • 61
  • 1
    The functions you're showing seem to return hashes instead of arrays or is {0: "test"} a synonym for ["test"]? – greg0ire May 02 '12 at 14:10
1

Use:

var myHash = {"apples": 3, "oranges": 4, "bananas": 42}
vals=(function(e){a=[];for (var i in e) a.push(e[i]); return a;})(myHash).join(',')
keys=(function(e){a=[];for (var i in e) a.push(  i ); return a;})(myHash).join(',')
console.log(vals,keys)

Basically:

array=(function(e){a=[];for (var i in e) a.push(e[i]); return a;})(HASHHERE)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
test30
  • 3,496
  • 34
  • 26
-1

Here is a good example of array_keys from PHP.js library:

function array_keys (input, search_value, argStrict) {
    // Return just the keys from the input array, optionally only for the specified search_value

    var search = typeof search_value !== 'undefined',
        tmp_arr = [],
        strict = !!argStrict,
        include = true,
        key = '';

    for (key in input) {
        if (input.hasOwnProperty(key)) {
            include = true;
            if (search) {
                if (strict && input[key] !== search_value) {
                    include = false;
                }
                else if (input[key] != search_value) {
                    include = false;
                }
            }

            if (include) {
                tmp_arr[tmp_arr.length] = key;
            }
        }
    }

    return tmp_arr;
}

The same goes for array_values (from the same PHP.js library):

function array_values (input) {
    // Return just the values from the input array

    var tmp_arr = [],
        key = '';

    for (key in input) {
        tmp_arr[tmp_arr.length] = input[key];
    }

    return tmp_arr;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
VisioN
  • 143,310
  • 32
  • 282
  • 281
  • The functions you're showing seem to return hashes instead of arrays or is {0: "test"} a synonym for ["test"]? – greg0ire May 02 '12 at 14:11
  • @greg0ire They are not synonymous. `{0: "test"}` is an instance of `Object`, while `["test"]` is an instance of `Array`. But both of them have member `0` of value `"test"`. – Imp May 02 '12 at 14:17
  • There are objects and arrays in JavaScript. Hash you are talking about is an object. If you have a look at the line with `var tmp_arr = []`, it shows that `tmp_arr` variable is an array (`[]`) but not an object (`{}`). So both methods return arrays. – VisioN May 02 '12 at 14:18
  • I was saying that because your functions seem to be the same as what Surreal Dreams proposed, and the links he gives say that both functions should return hashes. – greg0ire May 02 '12 at 14:25
  • This is because functions provided by PHP.js use internal methods `keys()` and `values()` that might return objects, since for JavaScript iteration `{ 0 : 'a', 1 : 'b' }` and `['a', 'b']` are the same. I have updated the functions above so that they will return arrays only. – VisioN May 02 '12 at 14:36