
JavaScript Equality Table - antoinec
http://dorey.github.io/JavaScript-Equality-Table/
======
dustingetz
There is a followup article "Don't Make Javascript Equality Look Worse Than It
Is"

"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...](http://strilanc.com/visualization/2014/03/27/Better-JS-Equality-
Table.html)

~~~
anonfunction
Amazing how the same data does make more sense visually when ordered this way
but still not compared to ==='s straight line.

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/](http://jsfiddle.net/4c5z60qg/) or view as an
image here: [https://i.imgur.com/assIoqN.png](https://i.imgur.com/assIoqN.png)

~~~
robocat
You can make it look prettier, but it doesn't make the underlying problem any
clearer.

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).

------
sheetjs
The rules are fairly simple: [http://www.ecma-
international.org/ecma-262/5.1/#sec-11.9.3](http://www.ecma-
international.org/ecma-262/5.1/#sec-11.9.3)

~~~
andrewchambers
Simple, and silly. Implicit conversion of string to number is asking for
problems.

~~~
jessedhillon
Do you often find that you have no idea whether your variable contains a
string or a number? Either your data comes from user input, an API, or some
file-like source. If it's user input, say from an <input>, you would already
know to parseInt(). If it's from an API then presumably it's conforming to a
documented spec. If it's from a file or something less than conformant, safely
parse it.

Why/how would you get to the point where you're operating on the value without
being certain of its type?

~~~
sheetjs
> Why/how would you get to the point where you're operating on the value
> without being certain of its type?

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](http://gazit.me/2012/01/09/Twitter-documentation-fail.html)

~~~
jessedhillon
How could === defend you in this case? `"100+" != 100` already.

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.

~~~
_ZeD_
yes, but ``"100+" > 100`` is ``false``

~~~
jessedhillon
So... you'd have to parseInt anyway?

------
judah
I like the end of the article. "Use three equals unless you fully understand
the conversions that take place for two-equals."

Or better said, "Always use 3 equals unless you have a good reason to use 2."

~~~
Xophmeister
Your rephrasing is better. For example, there's no reason to do:

    
    
        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](http://www.ecma-
international.org/ecma-262/5.1/#sec-11.4.3)

~~~
hajile
Removing a single character is hardly worth the issues that may arise from not
using it. The only quasi-acceptable use of '==' IMHO is:

    
    
        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).

~~~
paracaidista
== vs. === aside, it's a bit hypocritical to use === because it's safer when
you're using undefined as a keyword. You can't tell just from looking at that
line whether the variable undefined is actually undefined or not; it could, in
fact, be defined (below the global scope, that is -- unless you're in an older
browser, I suppose).

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.)

------
farnsworth

      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?

~~~
Groxx
I forget the specifics of Javascript, but in many languages "truthy" (used in
ifs) is usually closer to "!= false" than "== true". e.g. _any_ object or non-
zero number is truthy (except "" in JS), but only a handful are actually ==
true or == false.

~~~
farnsworth
Good point, same in JS:

    
    
      if (2 != false) console.log('yes')
      > yes
    

false goes to 0 and 2 != 0.

------
jessedhillon
Most of these scenarios are mitigated by knowing what types of data are coming
into your functions. If you're defending against a string being compared to a
number, I'd sooner wonder why you don't know whether you have a string or a
number in your variable in the first place. What could cause you to attempt to
use `[1]`(array containing number 1 as an element) as a boolean? Seems like
you should know if a variable contains an array and not true/false, and if you
don't then that's a better place to focus your attention.

Happy to hear counterexamples though.

~~~
UweSchmidt
If my "number" is in fact a string I'd like to get an error instead of a type
conversion that hides this error. This might not necessarily be an ignorant
beginner mistake, but may very well be a manifestation of some complicated bug
or error on the other end of the program, possibly in a library I haven't
studied enough and made assumptions about, or a black-box webservice.

I can handle it but don't see why I would go out of my way to defend
Javascript in this regard.

~~~
jessedhillon
> _If my "number" is in fact a string I'd like to get an error instead of a
> type conversion that hides this error._

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 ===

~~~
robocat
Wrong jessedhillon, becaue parseInt() is as quirky as == (this is JavaScript,
remember!).

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.

~~~
UweSchmidt
Yes, it's parseInt() plus some further checks if the results are within an
expected range in my code. And overall being more verbose, explicit, and
careful. And the occasional squinting eyes from the "Fry meme".

------
ambrop7
It immediately grabbed my attention that they used images for the column
labels. Vertical text should be doable with CSS.

~~~
martinml
It is!

[https://developer.mozilla.org/en-
US/docs/Web/CSS/transform#r...](https://developer.mozilla.org/en-
US/docs/Web/CSS/transform#rotate)

[http://caniuse.com/#feat=transforms2d](http://caniuse.com/#feat=transforms2d)

------
thisisblurry
This reminds me of Miłosz Kośmider's "Zeros in JavaScript" comparison table:
[http://zero.milosz.ca/](http://zero.milosz.ca/)

Essentially the same thing, but covers a few more operations.

------
userbinator
All dynamically typed languages with implicit coercion will have similar-
looking tables:

PHP:
[http://www.blueshoes.org/en/developer/php_cheat_sheet](http://www.blueshoes.org/en/developer/php_cheat_sheet)

Perl: [http://qntm.org/equality](http://qntm.org/equality)

Python:
[http://i.stack.imgur.com/Ya0Ux.png](http://i.stack.imgur.com/Ya0Ux.png) (I
don't think all the entries are correct)

~~~
name_censored_
> Python:
> [http://i.stack.imgur.com/Ya0Ux.png](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]

~~~
userbinator
I see the problem - the empty string is in a different position between the
rows and columns, leading to "" being equal to the string "True", which is
false.

------
stefek99
Object plus object is not a number :)

[https://www.destroyallsoftware.com/talks/wat](https://www.destroyallsoftware.com/talks/wat)

~~~
hajile
That's because the first 'object' is a block instead of an object literal.

------
jakub_g
Interesting, I didn't know about `[1] == true`, `[0] == false` family of
equalities.

Edit: it seems more general, `42 == [42]` etc. holds.

Edit: more fun

    
    
      ([0])==false // true
     !([0])==false // true

~~~
serve_yay
I am not sure what's up with the first two. But in the latter one, I believe
the array is being coerced to a string, which is its contents separated by
commas, so in this case just "42". Then either the left-hand 42 is coerced to
a string or the right-hand "42" is coerced to a number, I'm honestly not sure.
It hasn't been all that long since I read the spec about this, either. Sheesh.

------
prezjordan
Well, at least it's got some symmetry to it!

~~~
skrebbel
That's actually pretty important: it means that == and != are commutative.
Imagine the "wat" if that wasn't the case either. And hey, it's JS, it
could've been.

~~~
sheetjs
Commutative but not transitive, as in the example

    
    
        var x = {toString:function() { return "foo"; } }, y = "foo", z = new String("foo")
    

x == y and y == z but x != z

~~~
_asummers
This implies there is no equivalence relation with == in JS. In order to form
an equivalence relation, it would need to be reflexive, symmetric and
transitive.

------
rnhmjoj
"[] == []" and also with "===" is false. Why they choose not to use these for
array comparisons?

~~~
Kiro
They are. What do you mean?

~~~
rnhmjoj
It's useless since it's always false (unless you are comparing the same
variable).

> [1,2,3] == [1,2,3]

false

------
kelvin0
Going to the link made my Firefox (34.0.5) allocate over 2 GB of RAM... and
then everything stalled to molasses...

------
shurcooL
Can someone do this table for Go? I'm just curious to see it.

~~~
zamalek
It would likely just be the diagonal line in the middle, i.e. the === table.

------
SimeVidas
__tl;dr __ignore == and !=, use === and !== instead

------
duxet
i think this table was already posted many times - but this equality table
thing never gets boring :D

------
Buge
It leaves out negative zero.

------
nijo108
At least it is commutative.

------
frou_dh
dynamic typing good

weak typing bad

