Why is {} + {} no longer NaN in Chrome console?

Solution 1:

Chrome devtools now automatically wrap everything that begins with { and ends with } in an implicit pair of parentheses (see code), to force its evaluation as an expression. That way, {} creates an empty object now. You can see this if you go back through the history (), the previous line will be contained in (…).

Why? I don't know, but I could guess it reduces confusion for newbies that don't know of the block-vs-object-literal thing, and it's also more helpful if you just want to evaluate an expression.

And in fact that's the reasoning, as discussed in bug 499864. Pure convenience. And because node REPL had it as well (see code).

Solution 2:

If you hit the up arrow after checking this, you'll notice that instead of {} + {} it displays ({} + {}), which results in "[object Object][object Object]".

In comparison, in Firefox, {} + {} still displays NaN, but if you do ({} + {}) it also displays "[object Object][object Object]".

So, it looks like Chrome is adding the surrounding parenthesis automatically when it sees this operation.

Solution 3:

As of Chrome 54 with regards to the console:

📎-"I converted that block to an Object for you" -Clippy Unfortunately, I added the Clippy quote myself. The console gives no information about what it has done for you.

The new rules are incredibly simple saving us the trouble of laboriously typing these 2 difficult charcters o= or 0, before pasting Object Literals into the console:

  • If you have code that starts with: optional whitespace,(no comments permitted) followed by a {;
  • and that code could be interpreted as an object;
  • and that object is followed by no other code, unless:
  • the code after the first object is a binary operator,
  • then there can be as many operations as you like including groupings
  • provided the final operator has an Object literal in the right hand position;
  • and that final Object has not been grouped in parens
  • and that code is not terminated with a semicolon
  • and there are no comments following the code (internal comments are permitted so long as they are not in the initial or final position)
  • then and only then will your JavaScript (which may or may not actually be valid code) will be re-intrepted as a valid Object. You will not be informed that your code has been reinterpreted.

{wat:1}),({wat:2} Is finally an error again.

{let i=0;var increment=_=>i++} is correctly allowed, finally, which is quite a nice way of doing closures.

However, the following is incorrectly an object, this is just as a convenience as mentioned by @Bergi, it interprets JS wrong to help you! The spec says it is a block with a labeled statement "foo" with a literal 1 that is not assigned to anything.

{foo:1}

The above should be the same as

if(1) {
    foo: 1
}

The following is treated correctly as a block... because it has a comment in front of it!

//magic comment
{foo:1}

So is this:

{foo:1}
//also magic

This is an Object:

{foo:
//not so magic comment
1}

This is an error

//not so magic comment
{foo:1}.foo

So is this:

{foo:1}.foo

This is fine:

1..wat

undefined

so is this:

['foo'][0]

The next one is correctly interpreted as an object whacked into the expression position with a 0, which is generally how we unambiguously ensure we have an expression instead of a statement.

0,{foo:1}.foo

I don't get why they wrap the value in parens. JS has some ridiculous design decisions, but trying to make it behave nicer in this one situation isn't really an option, the console needs to run JS correctly, and we need to be confident that chrome isn't just guessing that it thinks we really meant it to do something else.

If you don't like comma operators you can use assignment

x = {foo:1}.foo

Because as it stands

{} + {} + {}

"[object Object][object Object][object Object]"

;{} + {} + {}

"NaN[object Object]"

Crazy and consistent I can deal with... crazy and inconsistent no thank you!