In the console of both FF and Chrome, {} is considered undefined until explicitly evaluated:
{}; // undefined
({}); // ▶ Object
Actually, it's a bit less defined than undefined -- it's apparently bad syntax:
{} === undefined; // SyntaxError: Unexpected token ===
{}.constructor; // SyntaxError: Unexpected token .
But not if it's on the other side, in which case it's fine:
"[object Object]" == {}.toString(); // true
Or if it's not the first expression:
undefined + undefined; // NaN
{} + undefined; // NaN
undefined + {}; // "undefined[object Object]"
What gives?
If you use the curly brackets by themselves, it's not an object literal, it's a code block. As the code block doesn't contain any code, evaluating it results in undefined
.
Okay, here is my answer. There is nothing new here. I am just linking to (a pretty copy of) the ECMAScript specification for the grammar and showing a few productions to show "why" it parses the way it does. In any case, the behavior is well-defined according to the JavaScript/ECMAScript grammar rules: {}
is parsed differently depending upon the "context" it is in.
The JavaScript REPLs ("consoles") start to parse the code in the Statement
grammar production or "statement context". (This is actually a lie, it starts at the Program
or SourceElements
production, but that adds additional constructs to dig through.) Here is a rough grammar breakdown with simplifications and omissions; see the link above for more:
Statement
Block
...
ExpressionStatement
Block
# This is actually { StatementList[optional] }, but this is what
# it amounts to: * means "0 or more".
{ Statement* }
ExpressionStatement
# An ExpressionStatement can't start with "{" or "function" as
# "{" starts a Block and "function" starts a FunctionStatement.
[lookahead ∉ {{, function}]Expression ;
Expression
# This is really PrimaryExpression; I skipped a few steps.
...
( Expression )
Thus (when in "statement context"):
{}
-> Block # with no StatementList (or "0 statements")
-> Statement
And:
({})
-> (Expression)
-> Expression
-> ExpressionStatement # omitted in productions below
-> Statement
This also explains why undefined === {}
parses as EXPR === EXPR -> EXPR -> STMT
and results in false when evaluated. The {}
in this case is in an "expression context".
In the case of {} === undefined
it is parsed as {}; === undefined
, or BLOCK; BOGUS -> STMT; BOGUS
, which is a Syntax Error. However, with the addition of parenthesis this changes: ({} === undefined)
is parsed as (EXPR === EXPR) -> (EXPR) -> EXPR -> STMT
.
In the case of {} + "hi"
it is parsed as {}; + "hi"
, or BLOCK; + EXPR -> STMT; EXPR -> STMT; STMT
, which is valid syntax even though it is silly (+
is unary in this case). Likewise, just as above, "hi" + {}
puts the {}
into an "expression context" and it is parsed as EXPR + EXPR -> EXPR -> STMT
.
The JavaScript console is just showing the result of the last Statement, which is "undefined" (well, "nothing" really, but that doesn't exist) for an empty {}
block. (This might vary between browsers/environments as to what is returned in this case, e.g. last ExpressionStatement only?)
Happy coding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With