Two classes of object are provided: ValueSet and ValueMap. They have similar interfaces to JavaScript's Set and Map. ValueSet and ValueMap allow equality of keys to be customized by overriding their isEqual and getHash methods and by default key equality is based on lodash's isEqual function, meaning object equality has value rather than reference semantics. In contrast, key equality for the predefined Set and Map objects is based on the "SameValueZero" algorithm, meaning objects are equal if they are the same object.
// Map doesn't do what we want.
let map = new Map()
map.set({x: 2, y: 3}, "Treasure")
map.size // 1
map.has({x: 2, y: 3}) // false
map.get({x: 2, y: 3}) // undefined
// ValueMap to the rescue!
let map = new ValueMap()
map.set({x: 2, y: 3}, "Treasure")
map.size // 1
map.has({x: 2, y: 3}) // true
map.get({x: 2, y: 3}) // "Treasure"
ValueMap and ValueSet compute hash values for objects and their properties such that property enumeration order doesn't affect the hash value. This means the computed hash values do not depend on the property insertion order or other property ordering schemes. This is accomplished in time linear in the number of properties, i.e. without sorting the properties. See the comments relating to the hash function in the source code for details.
In the underlying implementation, elements are stored in arrays that in turn are properties of a JavaScript object used as a hash table, where the property name is the hash value of the keys. Unlike JavaScript's Set and Map, element insertion order is not retained. When enumerating the elements of a ValueSet or ValueMap, the enumeration order is not defined.