23 ms·
JavaScript Equality Table
- prezjordan 12y agoWell, at least it's got some symmetry to it!
- skrebbel 12y agoThat'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 12y agoCommutative 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 12y agoThis 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.
- stromgo 12y agoMany such examples can be spotted in the table: [] == 0 == [[]] [1] == true == [1] ... There are even two examples with self-equality (x == x && y == y && z == z): "0" == false == "" "0" == 0 == ""
- deleted 12y ago[deleted]
- sheetjs 12y agoThe 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
- Scarbutt 12y agoExactly, this table just makes it look scary, newbies shouldn't see this ;)
- andrewchambers 12y agoSimple, and silly. Implicit conversion of string to number is asking for problems.
- jessedhillon 12y agoDo 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?
- andrewchambers 12y agoBugs happen when more than one programmer interface with each others code and the original intent was not clear enough.
- jessedhillon 12y agoInstead of using === everywhere, if you parse and cast your input to known types you also have the opportunity to catch errors where input is not conforming. 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.
- frou_dh 12y agodynamic typing good weak typing bad
- judah 12y agoI 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 12y agoYour 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
- Drakim 12y agoMight the === comparison be faster, since the underlying JavaScript engine doesn't need to determine how the two types should be cast back and forward to be compared?
- Xophmeister 12y agoYep, === will be quicker if the types are the same.
- mattdesl 12y agoWell, there is a reason: consistency. ;) 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.
- nawitus 12y agoIt's probably easier to set a linter to disallow "==" equality comparison globally instead of only when "===" is strictly necessary.
- SamReidHughes 12y agoYes there is a reason, because somebody reading the code is going to have to wonder why the heck you used a double-equals, and the code could be edited later in such a way that the triple-equals becomes relevant again.
- farnsworth 12y agoif (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?
- Xophmeister 12y ago`2` is truthy, but `==` forces a coercion, which ends up converting Boolean `true` to a number, which is 1 (`ToNumber(true) := 1` [1]), which is ostensibly not equal to 2. 1. http://www.ecma-international.org/ecma-262/5.1/#sec-9.3 http://www.ecma-international.org/ecma-262/5.1/#sec-9.3
- Groxx 12y agoI 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.
- deleted 12y ago[deleted]
- farnsworth 12y agoGood point, same in JS: if (2 != false) console.log('yes') > yes false goes to 0 and 2 != 0.
- farnsworth 12y agoWell I can answer that myself thanks to sheetjs' link to the spec. Case 1: From the section for 'if ()', http://www.ecma-international.org/ecma-262/5.1/#sec-12.5 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 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>)
- ambrop7 12y agoIt immediately grabbed my attention that they used images for the column labels. Vertical text should be doable with CSS.
- martinml 12y agoIt is! https://developer.mozilla.org/en-US/docs/Web/CSS/transform#rotate https://developer.mozilla.org/en-US/docs/Web/CSS/transform#r... http://caniuse.com/#feat=transforms2d http://caniuse.com/#feat=transforms2d
- stefek99 12y agoObject plus object is not a number :) https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat
- jakub_g 12y agoInteresting, 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 12y agoI 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.
- deleted 12y ago[deleted]
- ricardobeat 12y agoTranslation: "0" == 0 false == false
- duxet 12y agoi think this table was already posted many times - but this equality table thing never gets boring :D
- shurcooL 12y agoCan someone do this table for Go? I'm just curious to see it.
- deleted 12y ago[deleted]
- FuckGo 12y agoI don't get the fetishistic behavior towards Golang. I also saw this comment today. https://news.ycombinator.com/item?id=8799363 https://news.ycombinator.com/item?id=8799363 However, what I get even less is how every single person I've seen make a comment related to Go on an article unrelated to Go has been obviously dumb. Seriously, what kind of idiot thinks this question or the one linked above makes sense? No, no one should do this table for Go. Go is not a dynamically typed language. Go does not have type coercion. Go's rules of equality are simple and obvious with the only exceptions being interfaces (equality of the underlying values) and nil (works as you'd expect). Now please quit coding and never say the word Go again. It's a terrible language and you're a terrible person for commenting about it or using it. I swear, I see dumber people using Go than PHP now-a-days; perhaps I should applaud the Go team for being the only group capable of making a language so terrible and yet so popular since PHP4. Go learn a Haskell for greater good or, better yet, learn to delete your account and jump off a bridge so no-one has to suffer your terrible comments ever again.
- smt88 12y agoYour conviction and intelligence definitely show from your decision to use a throwaway to reply! Out of curiosity, what should people be using instead of Go? (And don't say Haskell, because surely you're more pragmatic than that.) I'm looking at Elixir now, but Go has a growing community and great concurrency. It seems to me that you perhaps hate any language that encourage or forces OO design, even though almost no one does real, widely-used, functional projects.
- codygman 12y ago> don't say Haskell, because surely you're more pragmatic than that What's that supposed to mean?
- jessedhillon 12y agoMost 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 12y agoIf 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 12y ago> 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 12y agoWrong 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.
- dustingetz 12y agoThere 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-Equality-Table.html http://strilanc.com/visualization/2014/03/27/Better-JS-Equal...
- anonfunction 12y agoAmazing 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 12y agoYou 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).
- rnhmjoj 12y ago"[] == []" and also with "===" is false. Why they choose not to use these for array comparisons?
- Buge 12y agoIt leaves out negative zero.
- userbinator 12y agoAll 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_ 12y ago> 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 12y agoI 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.
- tckr 12y agoIt's part of the official docs: http://php.net/manual/en/types.comparisons.php http://php.net/manual/en/types.comparisons.php
- thisisblurry 12y agoThis 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.
- kelvin0 12y agoGoing to the link made my Firefox (34.0.5) allocate over 2 GB of RAM... and then everything stalled to molasses...
- SimeVidas 12y agotl;dr ignore == and !=, use === and !== instead
- nijo108 12y agoAt least it is commutative.