/ #JavaScript #tip 

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' } ]
    }
  }
};

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;
}

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).

// Some of these fail even though
// 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)

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');

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);

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 !==/===.

Author

Hugo Di Francesco

A developer, working out of London writing CSS, JavaScript and Python.