When it comes to detecting arrays accurately and reliably, the current situation resembles the pre-ES5 methods. Refer to this insightful article for a deeper understanding of the potential pitfalls of implementing isArray
.
Various methods can be utilized:
obj.constructor == Map
/Set
, but this approach is ineffective with subclass instances and vulnerable to deception.
obj instanceof Map
/Set
, while functional, may fail across realms and can be tricked via prototype manipulation.
obj[Symbol.toStringTag] == "Map"
/"Set"
, which can be easily deceived again.
To ensure accuracy, testing for [[MapData]]
/[[SetData]]
internal slots is necessary, although these are not easily accessible as they are internal. However, a workaround exists:
function isMap(o) {
try {
Map.prototype.has.call(o); // throws if o is not an object or has no [[MapData]]
return true;
} catch(e) {
return false;
}
}
function isSet(o) {
try {
Set.prototype.has.call(o); // throws if o is not an object or has no [[SetData]]
return true;
} catch(e) {
return false;
}
}
For general use, utilizing instanceof
is recommended for its simplicity, understandability, performance, and effectiveness in most scenarios. Alternatively, one could opt for duck typing and focus on whether the object possesses has
/get
/set
/delete
/add
/delete
methods.