How Lodash isEmpty Handles Empty Map and Set
Lodash's _.isEmpty function evaluates Map
and Set instances by identifying their internal object
types and checking their native size property. Unlike
standard JavaScript objects that rely on enumerable keys to determine
emptiness, empty collections created via new Map() or
new Set() return true because Lodash detects
their specific collection tags and confirms that their size
equals 0.
Type Detection via Internal Tags
When a value is passed to _.isEmpty, Lodash first checks
for primitive nullish values and general object types. For complex data
structures, it uses an internal utility named getTag (which
relies on Object.prototype.toString.call(value)) to resolve
the exact internal category of the structure.
When evaluating a Map or a Set, the tag
resolves to:
[object Map][object Set]
This distinction is crucial. Plain JavaScript objects store entries
as standard enumerable properties, but Map and
Set store entries in internal slots that cannot be
discovered using standard methods like Object.keys().
The .size Property
Evaluation
Once Lodash identifies an object as a Map or
Set, it bypasses standard property enumeration and checks
the standard ES6 collection size property:
var tag = getTag(value);
if (tag == mapTag || tag == setTag) {
return !value.size;
}In JavaScript, Map.prototype.size and
Set.prototype.size return the number of elements contained
in the collection:
- A newly instantiated
new Map()ornew Set()has asizeof0. - A collection cleared with
.clear()has asizeof0.
Because 0 is falsy in JavaScript, the logical NOT
operator (!value.size) evaluates to true. When
items are added using .set() or .add(),
value.size returns an integer greater than 0,
causing !value.size to return false.
Why Standard Object Checks Would Fail
If Lodash treated Map and Set as generic
objects, _.isEmpty would produce incorrect results. Generic
object validation checks the length of own enumerable string-keyed or
Symbol-keyed properties:
const map = new Map([['key', 'value']]);
console.log(Object.keys(map).length); // Output: 0Even though the Map contains an entry, it possesses zero
own enumerable properties. By explicitly intercepting the
Map and Set tags and checking the
.size property directly, Lodash ensures that collections
without entries correctly return true, while collections
containing entries return false.