-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Primitive wrappers are always considered equal #73
Comments
TIL that "primitive wrapper" is actually the term to use. Would not have expected that, but I stand corrected! const number = new Number(1);
console.log(typeof number); // object
console.log(number === 1); // false Nonetheless, this is an interesting issue. The reason these are always equal is because the value of the constructed object is not stored on an own property, but rather a hidden slot whose value is only accessible via I'll need to consider how to approach this, because this return a.valueOf() === b.valueOf() || areObjectsEqual(a, b, isEqual, meta); This should solve the comparisons you are talking about with little additional cost, with the one caveat that true primitives would not be considered equal to their object class instance comparables ( // original
if (a && b && typeof a === 'object' && typeof b === 'object') {
// change
if (a && b && typeof a === 'object' && typeof b === 'object') {
a = a.valueOf();
b = b.valueOf(); This would allow comparisons like I'll noodle over this. |
I'm not quite sure what the right way is -- if I felt sure, I'd have made a concrete suggestion.
I think that would be acceptable (and as it happens, it would also suit my use case). It's the false equality that strikes me as downright misleading (as well as making our use case problematic).
In some code I had, I was just explicitly checking for the wrapper types to unwrap (obviously it wouldn't be exactly the same here): if (a !== null && typeof a === 'object') {
if (a instanceof Number || a instanceof Boolean || a instanceof String || a instanceof BigInt) {
a = a.valueOf();
}
} But of course this is But still, this is why I suggested that it could be gated by a flag or something to opt into, or opt out of, the mode where it checks for primitive wrappers, which after all are very rarely used. (We don't plan to use them, we just need this part to be bulletproof.) I guess one could just unconditionally call I don't know...I expect you know rather better than I do what is fast (and what speed tradeoffs are acceptable). |
Yeah this is a tough one. I'll need to noodle on it for a bit. Out of curiosity, do you know how other equality libraries handle this scenario? Lodash, ramda, etc? |
I don't, alas. The only one I've compared this library to so far is |
Alright, after some digging I went with a more targeted This fix is included in |
OK. But...
That doesn't seem right. And...
...Well, huh.
This strikes me as counterintuitive and seems incorrect. I could perhaps live with case 1 returning
false
, ornull
, orundefined
: if comparing two objects of some type the library isn't prepared to handle, I wouldn't be too surprised if it refused to return a boolean result, or just couldn't 'guarantee' that they're the same. But stating thatnew Number(1)
is equal tonew Number(2)
seems wrong in a surprising way.I thought about creating a custom comparator, but then I'd have to reimplement the circular check, as the library doesn't expose the
./utils
code.It would be nice if maybe
circularDeepEqual
function could accept some optional parameter to provide a comparison, or a flag, or a preprocessor callback (though that would presumably be slower).The text was updated successfully, but these errors were encountered: