How Lodash isSet Distinguishes Set from WeakSet
This article explains how the Lodash utility function
_.isSet identifies standard Set instances and
reliably excludes WeakSet collections. It details the
underlying type-checking mechanisms Lodash applies, including internal
string tags, Node.js native type bindings, and the structural
differences between these two built-in JavaScript objects.
The Core Implementation of
_.isSet
Lodash determines whether a given value is a standard
Set through an environment-aware approach. In modern
environments (such as Node.js), it prioritizes native type identifiers.
In standard browser environments or runtimes without native helpers, it
falls back to internal tag checks via
Object.prototype.toString.
In both approaches, WeakSet instances are explicitly
excluded because JavaScript treats Set and
WeakSet as fundamentally distinct types with different
internal slots.
Fallback
Mechanism: baseGetTag and [object Set]
In the standard fallback implementation (baseIsSet),
Lodash performs two primary checks:
Object-Like Validation (
isObjectLike):
The target must not benull, and itstypeofresult must be'object'. BothSetandWeakSetpass this initial check.Internal Tag Extraction (
getTag):
Lodash calls an internal utility,baseGetTag, which relies onObject.prototype.toString.call(value).JavaScript defines different
Symbol.toStringTagvalues forSetandWeakSet:Object.prototype.toString.call(new Set())evaluates to"[object Set]"Object.prototype.toString.call(new WeakSet())evaluates to"[object WeakSet]"
Lodash compares the extracted string directly against the constant
setTag ("[object Set]"):
const setTag = '[object Set]';
function baseIsSet(value) {
return isObjectLike(value) && getTag(value) == setTag;
}Because new WeakSet() yields
"[object WeakSet]", the condition evaluates to
false.
Native Node.js Type Checks
In Node.js environments, Lodash attempts to load the internal
util.types module (specifically
util.types.isSet via nodeUtil.isSet).
Node's native util.types.isSet inspects the V8 engine's
internal slots. A Set instance possesses the internal slot
[[SetData]], whereas a WeakSet possesses
[[WeakSetData]].
- Node's
isSetreturnstrueonly if the[[SetData]]internal slot is present. - Node maintains a separate function,
util.types.isWeakSet, exclusively for checking[[WeakSetData]].
When nodeUtil.isSet is available, Lodash wraps it
directly:
const isSet = nodeIsSet ? (value) => nodeIsSet(value) : baseIsSet;Why WeakSets Cannot Mimic Sets
WeakSet is designed solely for holding weakly referenced
objects and lacks the iterable interface, the .size
property, and collection traversal methods (.forEach(),
.values(), .keys()).
Because Lodash relies strictly on non-forgeable internal mechanics
(either V8 internal slots via Node bindings or default
Symbol.toStringTag evaluation through getTag),
a WeakSet cannot trigger a false positive in
_.isSet. Lodash provides a separate method,
_.isWeakSet, to target WeakSet instances
specifically by matching against "[object WeakSet]" or
util.types.isWeakSet.