DEV Community

Cover image for Detecting Object vs Array in JavaScript by example
Hugo Di Francesco
Hugo Di Francesco

Posted on • Originally published at codewithhugo.com on

Detecting Object vs Array in JavaScript by example

Let’s say we want to measure the depth of we have an object with mixed nested arrays/objects like so:

const obj = {
  myKey: {
    nest: {
      doubleNested: 'value',
      nestedArray: [ { key: 'value' } ]
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

The difficulty lies in detecting whether we should treat the value as an object (dictionary) or as a list.

We should be able to do this with the following:

function maxDepth(obj, depth = 0) {
  if (typeof obj !== 'object') {
    return depth;
  }
  const [values, depthIncrease] = Array.isArray(obj)
    ? [obj, 0]
    : [Object.values(obj), 1];
  return values.length > 0
    ? Math.max(...values.map(
      value => maxDepth(value, depth + depthIncrease))
    )
    : depth;
}
Enter fullscreen mode Exit fullscreen mode
// Some of these fail even although
// the assertions hold 🙄
console.assert(maxDepth({}), 0);
console.assert(maxDepth(''), 0);
console.assert(maxDepth([ { one: 'deep' } ]), 1);
console.assert(maxDepth({ one: 'deep' }), 1);
console.assert(maxDepth({ one: [ { two: 'deep' } ] }), 2)
console.assert(maxDepth({ one: { two: 'deep' } }), 2)
Enter fullscreen mode Exit fullscreen mode

To break down object vs primitive type detection, it’s a case of typeof obj === 'object', see this quick reminder of types of things:

console.assert(typeof '', 'string');
console.assert(typeof new String(), 'string');
console.assert(typeof 1, 'number');
console.assert(typeof Infinity, 'number');
console.assert(typeof NaN, 'number');
console.assert(typeof undefined, 'undefined');

console.assert(typeof [], 'object');
console.assert(typeof null, 'object');
console.assert(typeof {}, 'object');
console.assert(typeof new Map(), 'object');
console.assert(typeof new Set(), 'object');
Enter fullscreen mode Exit fullscreen mode

Now to separate Objects vs Arrays it’s Array.isArray every day, although we could use a check on .length, there’s also the caveat of Set or Map being passed around the function:

// Console.assert flips out again
// even though the assertions hold
console.assert(Array.isArray({}), false);
console.assert(Array.isArray(new Map()), false);
console.assert(Array.isArray(new Set()), false);

console.assert(Array.isArray([]), true);
console.assert(Array.isArray(new Array()), true);
Enter fullscreen mode Exit fullscreen mode

We could also use .length > 0, although that will check for a non-empty Array, or .length != null, and that’s a great use case for !=/==, but let’s stay away from that lest someone changes it to a !==/===.

This was sent out on the Code with Hugo newsletter last Monday.
Subscribe to get the latest posts right in your inbox (before anyone else).

Top comments (1)

Collapse
 
0x04 profile image
Oliver Kühn • Edited

Had to mention a very simple way to detect the real data class:

const is = (object, isType = null) => {
  var type = Object.prototype.toString.call(object).slice(8, -1);
  return (isType) ? type === isType : type;
}

is([1, 2, 3], 'Array') // true
is(document) // 'HTMLDocument'

Source: Using toString() to detect object class