Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When (and why) is {} undefined in a JavaScript console?

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?

like image 813
JS_Riddler Avatar asked Mar 29 '12 22:03

JS_Riddler


2 Answers

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.

like image 173
Guffa Avatar answered Oct 14 '22 10:10

Guffa


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.

like image 32
12 revsuser166390 Avatar answered Oct 14 '22 10:10

12 revsuser166390