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;
}
// 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)
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 !==
/===
.
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)
Had to mention a very simple way to detect the real data class:
Source: Using toString() to detect object class