I just want to check that an object is a Map
or Set
and not an Array
.
to check an Array I'm using lodash's _.isArray
.
function myFunc(arg) {
if (_.isArray(arg)) {
// doSomethingWithArray(arg)
}
if (isMap(arg)) {
// doSomethingWithMap(arg)
}
if (isSet(arg)) {
// doSomethingWithSet(arg)
}
}
If I were to implement isMap
/isSet
, what does it need to look like? I'd like for it to be able to catch subclasses of Map
/Set
if possible as well.
The situation is similar to pre-ES5 methods to detect arrays properly and reliably. See this great article for the possible pitfalls of implementing
isArray
.We can use
obj.constructor == Map
/Set
, but that doesn't work on subclass instances (and can easily be deceived)obj instanceof Map
/Set
, but that still doesn't work across realms (and can be deceived by prototype mangling)obj[Symbol.toStringTag] == "Map"
/"Set"
, but that can trivially be deceived again.To be really sure, we'd need to test whether an object has a
[[MapData]]
/[[SetData]]
internal slot. Which is not so easily accessible - it's internal. We can use a hack, though:For common use, I'd recommend
instanceof
- it's simple, understandable, performant, and works for most reasonable cases. Or you go for duck typing right away and only check whether the object hashas
/get
/set
/delete
/add
/delete
methods.You can use the
instanceof
operator:If the candidate object has
Set.prototype
in its prototype chain, then theinstanceof
operator returnstrue
.edit — while the
instanceof
thing will work most of the time, there are situations in which it won't, as described in Bergi's answer.