Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reliably check an object is an EcmaScript 6 Map/Set?

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.

like image 423
nackjicholson Avatar asked Apr 28 '15 16:04

nackjicholson


People also ask

How do you check if an object is a map?

Use the instanceof operator to check if an object is a Map - myObj instanceof Map . The instanceof operator returns true if the prototype property of a constructor appears in the prototype chain of the object.

How do you check if something is a map in JS?

The Map.has() method in JavaScript is used to check whether an element with a specified key exists in a map or not. It returns a boolean value indicating the presence or absence of an element with a specified key in a map.

What are sets and maps in ECMAScript 6?

ECMAScript 6 formally introduces sets and maps into JavaScript. Prior to this, developers frequently used objects to mimic both sets and maps, often running into problems due to the limitations associated with object properties. Sets are unordered lists of unique values.

What is WeakMap in ECMAScript 6?

The ECMAScript 6 WeakMap type is an unordered list of key-value pairs, where a key must be a non-null object and a value can be of any type. The interface for WeakMap is very similar to that of Map in that set () and get () are used to add and retrieve data, respectively:

How do I use arbitrary keys in ECMAScript 6?

The Map data structure in ECMAScript 6 lets you use arbitrary values as keys and is highly welcome. Working with single entries: Determining the size of a map and clearing it: You can set up a map via an iterable over key-value “pairs” (arrays with 2 elements). One possibility is to use an array (which is iterable): What keys are considered equal?

What is the data structure of ECMAScript 5?

ECMAScript 5 doesn’t have a set data structure, either. There are two possible work-arounds: Use the keys of an object to store the elements of a set of strings. Store (arbitrary) set elements in an array: Check whether it contains an element via indexOf (), remove elements via filter (), etc.


1 Answers

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:

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 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 has has/get/set/delete/add/delete methods.

like image 130
Bergi Avatar answered Oct 02 '22 13:10

Bergi