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