The situation is similar to pre-ES5 methods for the correct and reliable detection of arrays. See this great article for possible pitfalls of isArray implementation.
We can use
obj.constructor == Map / Set , but this does not work on instances of the subclass (and can be easily fooled)obj instanceof Map / Set , but this still doesn't work across spheres (and can be tricked with the prototype mangling)obj[Symbol.toStringTag] == "Map" / "Set" , but this can be trivially tricked again.
To be sure, we need to check if the object has an internal [[MapData]] / [[SetData]] . Which is not so easily accessible - it is internal. However, we can use the hack:
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, I would recommend instanceof - it is simple, understandable, efficient and works in the most reasonable cases. Or, you immediately type a duck and check to see if the object has / get / Set / delete / add / delete methods.
Bergi source share