Lodash Fallback Mechanism When Native Set Is Missing
When running in legacy JavaScript environments where the ECMAScript
2015 (ES6) native Set object is unavailable, the Lodash
library falls back to an internal tiered caching architecture. Primarily
managed through an internal constructor called SetCache,
Lodash delegates storage and lookup operations to MapCache.
This mechanism allows functions requiring uniqueness checks—such as
_.uniq, _.difference, and
_.intersection—to function reliably without throwing
runtime errors, gracefully degrading lookup performance from constant
time \(O(1)\) to linear time \(O(n)\) when dealing with complex
objects.
Feature Detection with
getNative
Before utilizing native modern features, Lodash checks the runtime
environment using an internal utility called getNative.
var Set = getNative(root, 'Set');The getNative function verifies that Set
exists on the global object (window, global,
or self) and ensures its implementation consists of native
code rather than an incomplete or incompatible userland polyfill. If
this check fails, Lodash sets its internal reference to
undefined and switches to polyfilled data structures.
The Role of SetCache
Methods that rely on set operations do not interface directly with
native arrays or modern sets. Instead, Lodash routes collection data
through an internal SetCache class.
When Set is natively available, SetCache
creates an instance of native Set to store values. When
Set is unavailable, SetCache initializes an
internal instance of MapCache:
function SetCache(values) {
var index = -1,
length = values ? values.length : 0;
this.__data__ = new MapCache;
while (++index < length) {
this.add(values[index]);
}
}Because a set only requires checking for key existence,
SetCache.prototype.add stores the item as a key inside
MapCache paired with a constant dummy value
(HASH_UNDEFINED).
The MapCache Fallback
Tiers
The MapCache implementation handles missing native
collections through a composite data structure composed of two main
fallbacks:
HashCache: Used for primitive keys such as strings, numbers, and symbols. It avoids prototype pollution by utilizingObject.create(null)or plain objects with stripped prototypes. Lookups against theHashcache remain near \(O(1)\) complexity because keys map directly to object properties.ListCache: Used when keys are complex objects or reference types that cannot safely be converted to string keys without collisions.ListCachestores entries in an internal array of two-element arrays ([[key, value]]). Lookups are performed via linear search using theSameValueZerocomparison algorithm. In the absence of nativeSetorMap, object deduplication drops to \(O(n)\) search time per item, leading to \(O(n^2)\) overall performance for utilities like_.uniq.
Iteration and Array Scanning Fallbacks
In certain lightweight operations or small collection sizes
(typically fewer than 200 elements), Lodash skips cache initialization
entirely. Instead, it relies on direct array scanning utilities like
arrayIncludes and arrayIncludesWith. These
functions use simple iteration loops over native arrays, bypassing the
overhead of creating fallback cache instances when processing small data
sets.