The main flow of code is a place that is not part of an expression.
Here are language moments that can only be placed in the main code flow:
- function declaration (different from function expression)
- code block (different from object)
- labels (different from property names)
- all syntactic constructions of the language: if, else, try, var, etc.
If there are two similar constructions, one of which can exist only in the main thread, then this criterion will be used to distinguish them: if the code is located in the main code flow, then the corresponding construction is chosen, and if in the expression, the other.
As for the {}+{} record, in the case of the main code flow, its value usually doesn’t go anywhere at all, although it is displayed in REPL environments as a result. The first brace means the opening of a block of code, then the second ends it. Then comes a plus - we have no left operand, which means it is unary. We are already in expression. A curly brace in an expression starts an object. Next - ends the object. It turns out +{} , then +"[object Object]" and NaN .
In the case of console.log , the function call itself forms an expression. Therefore, the first pair of parentheses turns into an object, and the entire sum after casting types into string concatenation.
The only way (at least in ES2018-) to get in the code is to pass a string with the code in eval.
function run(code) { try { console.log(eval(code)) } catch(e) { console.log(e.name + " " + e.message) } } run('{console.log("I am the code block")} + {i:0, am:1, an:2, object:3}') run('({a:0, pair:1} + {of:2, objects:3})') // круглые скобки run('{not_object:0} + {object:1}') // метка! run('{not_object:0, really_not:1} + {object:2}') // ошибка - метка не может быть вне основного потока run('{not_object:0; really_not:1} + {object:1}') // `;`, а не `,` - две метки
As for the chrome console - apparently they made a clever definition of whether something in curly braces is an object or a piece of code. Moreover, preference is given to the object. I think this is done for greater convenience, that if you enter an expression into the console, then you want the result of an expression that you will not get in the main code stream. But it is worth noting that this thing in the console only works for top-level-code (and even then not always), and does not apply to the embedded code:

{} + {}it givesNaN- andreymal