88

The output of my JSON call can either be an Array or a Hash. How do I distinguish between these two?

akshat
  • 15,472
  • 8
  • 30
  • 29

7 Answers7

141

Modern browsers support the Array.isArray(obj) method.

See MDN for documentation and a polyfill.

= original answer from 2008 =

you can use the constuctor property of your output:

if(output.constructor == Array){
}
else if(output.constructor == Object){
}
pawel
  • 35,827
  • 7
  • 56
  • 53
  • 2
    This has the potential of conflicts between different pages, since they both have different instances of the `Array` and `Object` constructor functions, that won't compare as equal. I'm not quite sure how to produce an example that demonstrates this, but I read it somewhere. – ripper234 May 14 '12 at 11:15
  • 1
    @ripper234 The problem will manifest itself in a multi `window` environment. – alex Nov 11 '12 at 03:55
  • 3
    +1 for metioning Array.isArray. Check this link for borwser support: http://kangax.github.io/compat-table/es5/#Array.isArray – SKuijers Mar 11 '15 at 13:47
  • 1
    Anybody using [underscore.js](http://documentcloud.github.io/underscore/) might find [isArray](http://documentcloud.github.io/underscore/#isArray) and [isObject](http://documentcloud.github.io/underscore/#isObject) useful. – akotian Jul 30 '15 at 16:56
  • 1
    @akotian _.isObject returns true for both array and hash, unfortunately. You'll need additional conditional logic to iron out a solution with underscore. – Con Antonakos Oct 19 '15 at 16:03
  • Pashmam!!! for more information see [this link](https://www.urbandictionary.com/define.php?term=Pashmam) – AmerllicA Aug 21 '18 at 07:39
38

Is object:

function isObject ( obj ) {
   return obj && (typeof obj  === "object");
}

Is array:

function isArray ( obj ) { 
  return isObject(obj) && (obj instanceof Array);
}

Because arrays are objects you'll want to test if a variable is an array first, and then if it is an object:

if (isArray(myObject)) {
   // do stuff for arrays
}
else if (isObject(myObject)) {
   // do stuff for objects
}
Borgar
  • 37,817
  • 5
  • 41
  • 42
12

Did you mean "Object" instead of "Hash"?

>>> var a = [];
>>> var o = {};
>>> a instanceof Array
true
>>> o instanceof Array
false
Jonny Buchanan
  • 61,926
  • 17
  • 143
  • 150
7

I made a function for determining if it's a dictionary.

exports.is_dictionary = function (obj) {
    if(!obj) return false;
    if(Array.isArray(obj)) return false;
    if(obj.constructor != Object) return false;
    return true;
};

// return true
test.equal(nsa_utils.is_dictionary({}), true);
test.equal(nsa_utils.is_dictionary({abc:123, def:456}), true);

// returns false
test.equal(nsa_utils.is_dictionary([]), false);
test.equal(nsa_utils.is_dictionary([123, 456]), false);
test.equal(nsa_utils.is_dictionary(null), false);
test.equal(nsa_utils.is_dictionary(NaN), false);
test.equal(nsa_utils.is_dictionary('hello'), false);
test.equal(nsa_utils.is_dictionary(0), false);
test.equal(nsa_utils.is_dictionary(123), false);
neoneye
  • 50,398
  • 25
  • 166
  • 151
  • Thanks for this. It has worked for the above cases mentioned. I have to yet come across a case where your method fails. – Nav Feb 08 '17 at 08:00
  • 1
    `if(Array.isArray(obj)) return false;` <- Isn't this redundant given that an array will not pass the next check anyway (`if(obj.constructor != Object)`)? –  Oct 30 '18 at 07:27
  • `assert.equal(is_dictionary(new (class MyClass {})), true);` fails - the instance of MyClass is definatelly a hash/dictionary. – Angelos Pikoulas Jan 30 '20 at 16:28
  • Improved it a bit: ```const assert = require('assert'); const is_dictionary = function (obj) { if(!obj) return false; if(Array.isArray(obj)) return false; if (({}).toString.apply(obj) !== '[object Object]') return false; return true; }; // returns true along your own with these values new (class MyClass {}) Object.create({}) Object.create(null) // returns false along with yours new String('foo') new Number(123) ()=> {} function() {} new Map ``` – Angelos Pikoulas Jan 30 '20 at 16:35
3

A more practical and precise term than object or hash or dictionary may be associative array. Object could apply to many undesirables, e.g. typeof null === 'object' or [1,2,3] instanceof Object. The following two functions work since ES3 and are mutually exclusive.

function is_array(z) {
    return Object(z) instanceof Array;
}

console.assert(true === is_array([]));
console.assert(true === is_array([1,2,3]));
console.assert(true === is_array(new Array));
console.assert(true === is_array(Array(1,2,3)));

console.assert(false === is_array({a:1, b:2}));
console.assert(false === is_array(42));
console.assert(false === is_array("etc"));
console.assert(false === is_array(null));
console.assert(false === is_array(undefined));
console.assert(false === is_array(true));
console.assert(false === is_array(function () {}));
function is_associative_array(z) {
    return String(z) === '[object Object]' && ! (Object(z) instanceof String);
}

console.assert(true === is_associative_array({a:1, b:2}));
console.assert(true === is_associative_array(new function Legacy_Class(){}));
console.assert(true === is_associative_array(new class ES2015_Class{}));

console.assert(false === is_associative_array(window));
console.assert(false === is_associative_array(new Date()));
console.assert(false === is_associative_array([]));
console.assert(false === is_associative_array([1,2,3]));
console.assert(false === is_associative_array(Array(1,2,3)));
console.assert(false === is_associative_array(42));
console.assert(false === is_associative_array("etc"));
console.assert(false === is_associative_array(null));
console.assert(false === is_associative_array(undefined));
console.assert(false === is_associative_array(true));
console.assert(false === is_associative_array(function () {}));

Notice how this will treat the instance of a class as an associative array. (But not the instance of a built-in class, such as Date.)

The && clause above is a brutish fix for this obscure white-box test:

console.assert(false === is_associative_array("[object Object]"));

Caution: these functions will not be efficient for large or many objects.

Bob Stein
  • 16,271
  • 10
  • 88
  • 101
2

Check for "constructor" property on the object. It is Array - it is an array object.


var a = {
 'b':{length:0},
 'c':[1,2]
}

if (a.c.constructor == Array)
   for (var i = 0; i < a.c.length; i++)
      alert(a.c[i]);
else
   for (var s in a.b);
      alert(a.b[s]);

Sergey Ilinsky
  • 31,255
  • 9
  • 54
  • 56
0

For parsing json could come in handy :)

isArrayHashs = (attr) ->
  !!attr && attr.constructor == Array && isHash(attr[0])

isHash = (attr) ->
  !!attr && !$.isNumeric(attr) && attr.constructor == Object

attr[0].constructor must be:

  • String
  • Numeric
  • Array
  • Object
  • Undefined
Viktor Ivliiev
  • 1,015
  • 4
  • 14
  • 21