9

So, there is one thing I can't get my head around.

I have no problem understanding that:

{}+[]+{}+[1]

gives

"0[object Object]1"

What I really don't get though is why

{}+[]+{}

gives

"[object Object][object Object]" and not "0[object Object]"

My understanding is that the first {} is a block statement and thus is ignored. We then do have +[]+{} which results in "0[object Object]"

What am I missing here ?

EDIT: Despite being about the same subject, the other question isn't mentioning the difference between a {} being interpreted by the console as a block code or as an object.

Scipion
  • 11,449
  • 19
  • 74
  • 139
  • 2
    [___Unary Plus___](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus_()) – Rayon Apr 11 '19 at 09:54
  • 1
    @Rayon OP is aware of unary plus. The question is why does the first `{}` in `{}+[]+{}` get parsed as object, but in `{}+[]+{}+[1]` as code block. I tried both expressions in esprima, and I can't see why they would be evaluated differently - but they are. – Amadan Apr 11 '19 at 09:58
  • 3
    Possible duplicate of [What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?](https://stackoverflow.com/questions/9032856/what-is-the-explanation-for-these-bizarre-javascript-behaviours-mentioned-in-the) – adiga Apr 11 '19 at 10:15
  • Yeah, not sure it's really worth digging through another Wat… ☝️ – deceze Apr 11 '19 at 10:18

1 Answers1

6

It depends in which syntactic position the parser is when you evaluate your expressions. Consider:

console.log(eval('{}+[]'), '==', eval('{}; +[]'))
console.log({}+[])

console.log('---')

console.log(eval('{}+[]+{}+[1]'), '==', eval('{}; +[] + {} + [1]'))
console.log({}+[]+{}+[1])

console.log('---')

console.log(eval('{}+[]+{}'), '==', eval('{}; +[] + {}'))
console.log({}+[]+{})

where "eval" blocks correspond to the "statement" position and bare "console.logs" are in the "expression" position. The leading {} is only treated as a block in the statement position.

> let esprima = require('esprima');
undefined

> esprima.parse('{}+[]+{}')
Script {
  type: 'Program',
  body:
   [ BlockStatement { type: 'BlockStatement', body: [] },
     ExpressionStatement { type: 'ExpressionStatement', expression: [BinaryExpression] } ],
  sourceType: 'script' }

> esprima.parse('( {}+[]+{} )')
Script {
  type: 'Program',
  body:
   [ ExpressionStatement { type: 'ExpressionStatement', expression: [BinaryExpression] } ],
  sourceType: 'script' }
> 

Note that when you evaluate your tests directly in the console or repl, the behaviour may differ from platform to platform, because consoles/repls use different heuristics to decide whether your input is a statement or an expression. See this answer for examples.

georg
  • 211,518
  • 52
  • 313
  • 390