25

Why in node.js is {} == {} equivalent to false, but is {} + {} == {} + {} equivalent to true?

> {} == {}
false
> {} + {} == {} + {}
true
apaderno
  • 28,547
  • 16
  • 75
  • 90
0xAX
  • 20,957
  • 26
  • 117
  • 206
  • 17
    Related: [WAT?](http://destroyallsoftware.com/talks/wat) –  Jul 21 '13 at 17:23
  • 2
    In Chrome it's false, just out of interest. – Rich Bradshaw Jul 21 '13 at 17:26
  • 1
    @RichBradshaw didn't test with Chrome, only with node. – 0xAX Jul 21 '13 at 17:27
  • 4
    I think a good answer to this question should address why node behaves different than the console in web browsers like chrome/ff – goat Jul 21 '13 at 17:27
  • Have you bothered logging the values you're comparing? –  Jul 21 '13 at 17:35
  • @chris: I've expanded my answer to address that. – ruakh Jul 21 '13 at 17:57
  • 2
    @RichBradshaw Of course it is, [**Chrome's dev tools JS console and NodeJS do REPL differently**](http://stackoverflow.com/questions/17268468/why-is-nan-only-on-the-client-side-why-not-in-node-js/17269376#17269376). – Benjamin Gruenbaum Jul 26 '13 at 22:39
  • possible duplicate of [What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?](http://stackoverflow.com/questions/9032856/what-is-the-explanation-for-these-bizarre-javascript-behaviours-mentioned-in-the) – SheetJS Oct 12 '13 at 03:44

1 Answers1

52

+ here is the string-concatenation operator. This:

{} == {}

means "if I create one object with {}, and another object with {}, are they the same object?"; and the answer is "no".

This:

{} + {} == {} + {}

means "is the primitive string "[object Object][object Object]" the same as the primitive string "[object Object][object Object]"?"; and the answer is "yes".


Edited to add: A number of commenters point out that in Chrome's Web Console, {} + {} performs numeric addition, NaN + NaN, such that {} + {} == {} + {} actually returns false (because it's not true that NaN == NaN). Firefox's Web Console gives the same result as Chrome's, but if you run this inside a page, it gives the same result as node.js.

[Redacted: long explanation of how the spec dictates that {} + {} should be string concatenation and {} + {} == {} + {} should be true; the explanation, while correct, is no longer terribly interesting, given the below.]


Edited to add: Thanks to a comment by jJ', I can now offer a better explanation of the inconsistency.

The reason for the Web Console's behavior is that the Web Console does not specifically require an expression; it will happily accept something like if(true) { }. So, when it sees {} + {}, it doesn't interpret that as an expression; the initial {} is interpreted as a naked block, then the + {} is interpreted as an expression (creating a new object, converting it to a primitive number — namely NaN — and evaluating to that number). The Web Console displays the result of the last expression (e.g., the input 3; 4 will give the output 4), which in this case is NaN.

{} + {} == {} + {}, similarly, is interpreted as "empty block, followed by (+{}) == ({} + {})", i.e., "empty block, followed by NaN == '[object Object][object Object]'", i.e. "empty block, followed by false".

This can be fixed by using parentheses; ({} + {} == {} + {}), for example, returns true.

(This behavior, by the way, is not completely specific to the Web Console. eval follows the same rules, such that eval('{} + {}') is NaN and eval('({} + {})') is'[object Object][object Object]'.)

Community
  • 1
  • 1
ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Yes, i saw "[object Object][object Object]" result from {} + {}, i'm new in node.js and did not pay attention that it is just a string, i thought that it's node's internal data type :), now i see that `typeof ({} + {})` is `string`. Thank you for great answer and explanation – 0xAX Jul 21 '13 at 17:34
  • @ruakh: Great explanation! Any thoughts on why `{} + {} == {} + {}` returns `false` in chrome and firefox? – go-oleg Jul 21 '13 at 17:37
  • 2
    @go-oleg Because in FF `{} + {}` is `NaN`. And `NaN == NaN` is false, because **NaN is never equal to itself**. See this explanation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FNaN – Daniel Kats Jul 21 '13 at 17:46
  • @go-oleg: I've expanded my answer to address that. It turns out to be pretty complicated! – ruakh Jul 21 '13 at 17:57
  • 4
    in chrome and FF console {} and ({}) are different things because of the ambiguity of block vs. object literal. "{} + {}" on the left hand side is like parse and ignore empty block "{}" and then try to convert object "{}" to a number using "+" because after the operator an expression is expected. on the right hand side it expects expression and so it concatenates two {}.toString(). So there is even more "trickery" there :). Node on the other hand uses a different way of evaluation, so it does not interpret an empty block. – jJ' Jul 22 '13 at 20:02
  • @jJ': Oh, that makes so much sense! I'll update the answer. Thank you! – ruakh Jul 22 '13 at 20:59
  • Welcome to the world of JavaScript. :) http://www.youtube.com/watch?v=THERgYM8gBM – freakish Jul 22 '13 at 23:34
  • 1
    See [my answer](http://stackoverflow.com/questions/17268468/why-is-nan-only-on-the-client-side-why-not-in-node-js/17269376#17269376) on why it behaves this way in Node's REPL but not in Chrome. – Benjamin Gruenbaum Jul 26 '13 at 22:41