JavaScript Equality Table
dorey.github.io
dorey.github.io
"These posts are fundamentally right about == being poorly designed... but they make things look worse by failing to organize the table.... What a mess! But most of the mess is because of the order of values in the table. By grouping equal values together, you get something more sensible"
http://strilanc.com/visualization/2014/03/27/Better-JS-Equal...
The author linked to a jsfiddle that I changed to use the same colors as the original table and improved the legibility a bit which you can find at http://jsfiddle.net/4c5z60qg/ or view as an image here: https://i.imgur.com/assIoqN.png
For example, few people would immediately be able to know where place the following into the table so that it still looked good:
['Infinity']
'0e1'
['infinity']
'0X0'
[false]
["+0.e4"]
[[[[1.,]]]]
and so on :) (A bit more time, and I could probably come up with even stranger examples).
Why/how would you get to the point where you're operating on the value without being certain of its type?
Your parsing makes it obvious to other programmers what your assumptions are about the input. With === all a person will see is that the expected condition did not trigger but no obvious reason why. If `key === 13` fails all we know is that there is no strict equality, but `parseInt(key) == 13` failing means that key is not something which could parse to number 13, and consequently what type(s) key can be is obvious.
Moreover with parseInt the left side of that operator will always be a number or NaN, and the right side is a scalar, so there is no justification for using `parseInt(key) === 13`. It would be preposterous. If you can't trust the return type of parseInt, then your programming environment is unreliable.
Tbh, I would suggest using something like typescript and having more granular types than just "number" and "string".
My favorite example of this is the twitter API, which used to report retweet count as the string "100+" for the case of over 100 retweets. This behavior was not documented [1], so until you encounter that example, you wouldn't necessarily expect this or defend against a string
[1] From 2012 http://gazit.me/2012/01/09/Twitter-documentation-fail.html
If you do a typeof before further processing the value then you'll know how to treat it, and additionally someone who comes after you will realize that the value could be a number or a string.
Or better said, "Always use 3 equals unless you have a good reason to use 2."
typeof someVar === 'number'
...because `typeof` always returns a string, by spec[1]1. http://www.ecma-international.org/ecma-262/5.1/#sec-11.4.3
I hate seeing "==" in code because it's rarely clear whether the programmer intends it to coerce or just didn't bother with the third keystroke. So "===" is just enforced everywhere through jshint.
myVar == null
as it is a little easier than: myVar === undefined || myVar === null
That said, I use only '===' as I don't want to ever worry about my code (plus, the use of a maybe monad makes this and other problems go away).Granted, defining a variable called undefined would be absurd, and I realize I'm nitpicking here, but if we're trying to make a point about good practice, typeof would be the way to go. (Of course, more often you only really care if something == null or not, so you'd just do a simple == null check, like you said.)
https://github.com/dorey/JavaScript-Equality-Table/commit/d7...
if (2) { console.log('yes') }
> yes
> undefined
if (2==true) { console.log('yes') }
> undefined
I would have thought these would be the same - what's the difference between being "truthy" in the first case, and being ==true, as in the second? if (2 != false) console.log('yes')
> yes
false goes to 0 and 2 != 0.Case 1: From the section for 'if ()', http://www.ecma-international.org/ecma-262/5.1/#sec-12.5,
If ToBoolean(GetValue(exprRef)) is true, ...
new Boolean(2) => true, so 2 is 'truthy' alone inside if ().Case 2: From the == section, http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3,
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
So the boolean is coerced to a number, and new Number(true) => 1. I wonder why they didn't do it the other way around, and make the number a boolean like above. You're losing seemingly useful information with new Number(<boolean>)Happy to hear counterexamples though.
I can handle it but don't see why I would go out of my way to defend Javascript in this regard.
If you expect a number or a string, call parseInt() on your value and then isNaN() on that will tell you whether you have an error condition. Your code will be more understandable if you spend time parsing your inpt and explicitly casting to expected types, rather than papering over differences with ===
parseInt('1 are you joking') returns 1.
parseInt('077') returns 63 on some older browsers (get off my octal lawn).
parseInt('0XALIC ACID') returns 10.
parseInt(' -1e5') returns -1.
And dealing with Integers in JavaScript is fraught with danger since browser JavaScript only really knows floating point numbers. e.g. parseInt('999999999999999999999999999999999999999999999999999999999999999999999999999999999') returns 1e+81...
Smoke that!
Edit: It is possible to build some reliable integer routines using logical operators (since they convert to unsigned integers to perform the operation) but one needs to understand the other underlying quirks to do so.
Essentially the same thing, but covers a few more operations.
PHP: http://www.blueshoes.org/en/developer/php_cheat_sheet
Perl: http://qntm.org/equality
Python: http://i.stack.imgur.com/Ya0Ux.png (I don't think all the entries are correct)
Python checks out;
>>> b=[True,False,1,0,-1,"","True","False","1","0","-1",None,[],{},[[]],[0],[1]]
>>> for x in b:
... print [int(y == x) for y in b]
...
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]{}+{}
doesn't mean what you might think it means.
Edit: it seems more general, `42 == [42]` etc. holds.
Edit: more fun
([0])==false // true
!([0])==false // true "0" == 0
false == false var x = {toString:function() { return "foo"; } }, y = "foo", z = new String("foo")
x == y and y == z but x != z[] == 0 == [[]]
[1] == true == [1]
...
There are even two examples with self-equality (x == x && y == y && z == z):
"0" == false == ""
"0" == 0 == ""
> [1,2,3] == [1,2,3]
false
weak typing bad