There are still so many basic things that aren't in the JS stdlib, though. A good example is Map - if you need to use a tuple of two values as a key, you're SOL because there's no way to customize key comparisons. Hopefully we'll get https://tc39.es/proposal-record-tuple/ eventually, but meanwhile languages ranging from C++ to Java to Python have had some sensible way to do this for over 20 years now.
const idx = [1,2]
const m = new Map
m.set(idx,"hi!")
console.log(m.get(idx)) // outputs "hi!"
console.log(m.get([1,2]) // outputs undefined
That last line has created a new array object, and Map is made to be fast so checks equality by reference. Ah, which is what you to be able to change. I guess you would want to pass a new map a comparator function, so that it does a deep equal. That would be faster than what you would have to do now:
const idx2 = String([1,2])
m.set(idx2, "yo")
console.log(m.get(idx2)) // yo
console.log(m.get(String([1,2])) // yo
That is precisely a key comparison issue. That is why I spoke about a tuple of two values; tuples by definition don't have a meaningful identity, so reference comparison is utterly meaningless for them.
Stringification is a very crude hack, and it doesn't even work in all cases - e.g. not if a part of your key still needs to be compared by reference. Say, it's a tuple of two object references, describing the association between those two objects.
Either way, the point is that this is really basic stuff that has been around in mainstream PLs for literally many decades now (you could do this in Smalltalk in 1980!).
There is a trivial way to have custom key comparisons: write a function that returns the key you want. You can implement equals() using some kind of serialization, or using a lookup table of references - whatever you want!
Of course, Records and Tuples would greatly simplify the process.
Writing a key comparison function is not a problem. The problem is that Map does not have any way to use such a thing; it always compares using a predefined equality algorithm that is by-reference for all aggregate data types.
I didn't say that you could pass a key comparison function directly into Map.
What I meant was that it's possible to emulate a custom key comparison predicate.
You just have to have a function that returns value for each input that behaves the way you want under strict equality comparison.
Implementing an `equals` function that returns a boolean is more convenient, sure.
Serializing (for plain objects with only JSON-serializable values that would be JSON.stringify) to strings or other primitives would of course be possible with object keys, too. But that's probably what you want for "record"-like objects, right?
And if you want better performance or compare non-primitive values, you'd have to do something more complex, that's what I meant by the lookup table.
But I imagine if you deep-compare large Record objects a lot, the performance wouldn't be any better, because the engine still has to do a deep comparison.
If I am not mistaken, Records/Tuples are in fact strictly limited to this case:
So basically there is no difference to having a function serialize() that just stringifies your plain object, maybe with a caching layer in between (WeakMap?)
OK, thinking about it, the proposal really would help to avoid footgun code where performance optimizations are lacking, and too many deep comparisons or too many serializations are performed.