Is the curly brackets object notation valid in any

2019-03-30 11:25发布

问题:

I'm currently analyzing the Javascript language a bit. It looks like you could group at lot of the concepts into a base type called expression. Even function arguments and definitions fit into that group, as well as strings, numbers and mathematical expressions. The only illogical exception was the curly bracket object notation in a nonsense alike context.

As functions consist of several expressions the following code is valid:

function valid(){
    /\W/;
    "ahll";
    var alpha;
    alpha;
    alpha={"first": 90, "second": 80};
    alpha;
    0, {"first": 90, "second": 80};
    [1,2,3];
    alpha;
    2+3;
    new RegExp("/\W/");
    return true;
}

By intention the following code should be valid too, but gets a "missing ; before statement" syntax error for the second line:

function invalid(){
    {"first": 90, "second": 80};
    return true;
}

The curly bracket object notation is accepted in every other case where expressions are accepted, except for these cases where a curly bracket code block would be allowed too.

Is the syntax error mentioned above caused by the implementation or the specification of javascript?

Is there a more precise name for such nonsense expression?

回答1:

Is the syntax error mentioned above caused by the implementation or the specification of javascript?

By the spec.

Is there a more precise name for such nonsense expression

You're looking for the term Expression Statement. As you say, Object literals are expressions (even primary expressions), just as most other things are. They can appear in many contexts, like function arguments, operands of an operator or inside brackets.

However, a function body - code - does not consist of expressions, it does consist of statements. That means things like if-statements, loop statements or plain blocks. Or "expression statements", which are nothing but an expression to be evaluated (and with side effects, they mostly are not "nonsense").

However, the spec mandates:

ExpressionStatement: [lookahead ∉ {{, function}] Expression ;

NOTE: An ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it ambiguous with a FunctionDeclaration.



回答2:

What you are viewing as an object, in the last example, is actually a block:

From the MDN:

A block statement is used to group zero or more statements. The block is delimited by a pair of curly brackets.

So, basically, when you start the curly braces, it understands it to be a block, and gives the error:

Uncaught SyntaxError: Unexpected token : 

Because it does not like those colons (:) inside of a block where it expects statements (var a = 2, etc.). It assumes that whatever follows the curly brace must be a set of statements, and hence is surprised to see the colon, and in confusion throws an error. Note that "first": 90 is not a valid statement.

Then why does 0, {"first": 90, "second": 80}; pass ?

Because after seeing the first expression (0), and then the comma operator, it expects to see another value of a similar type (i.e. another expression). And thus it treats the second object {"first": 90, "second": 80} as an object (which is also an expression) instead of a block.

To further simplify, try {"first": 90, "second": 80}, 0. Notice, it gives a SyntaxError exactly the same as the previous one. Because, once it sees the {, it treats the following as a block, and again complains for the colon (:).

How do I avoid this?

By making it a part of another expression, like:

( {1:2} ) // a block doesn't come inside parentheses
var a = {1 : 2}; // a block can't be the RHS
myFunc( { 1 : 5 } ) // a block can't be a function argument

Hope it helps!



回答3:

This has been addressed in a previous question here

Curly braces are used to either introduce a statement block, or as the start of an object literal. To handle this ambiguity, curly braces are interpreted as a statement block container by default, thus the syntax error in your example.

When the curly braces are used in the RHS of an operator, the ambiguity disappears; it is an object literal.



回答4:

The parser has the precedence to treat { as the starting of a block & not the start of an object.

So what do we do to explicitly tell reader to first add before multiply, in case of :

3 * 4 + 2

Perhaps this:

3 * (4 + 2)

Similarly for

{"first": 90, "second": 80};

we could do either this

({"first": 90, "second": 80}); 

or put it in various other ways where the parser understands your true intention.



回答5:

In ECMA-262 are many different types of Expressions defined. The "expression" mentioned in the opening Question matches best the PrimaryExpression, which is described like this: (each indented line is a possible representation)

PrimaryExpresion:
    this //as the 'this'-keyword
    Identifier //variable or function name ('alpha' in the question)
    Literal //string, number, mathematical expressions
    ArrayLiteral //[1,2,3]
    ObjectLiteral // {"first" : 80}
   ( Expression ) //An expression encapsulated in bracket

Curly bracket code block:

Block :
    { StatementList_opt } - A list of statements

Most relevant Statement in this case:

ExpressionStatement :
    [lookahead ∉ {{, function}] Expression ;

This allows only expression without an opening curly bracket or the 'function'-keyword at the beginning. (FunctionDeclarations are separated from statements and expressions, except for lambda functions which are FunctionExpression)

The Expression definition doesn't directly specify a PrimaryExpression but, over a long chain of definitions, PrimaryExpression can be considered as Expression:

Expression:
    AssignmentExpression
    Expression, AssingmentExpression

I did check the whole chain of definitions to see if PrimaryExpression is actually a Expression. Here is the definition chain:

Expression:
    AssignmentExpression:
        ConditionalExpression:
            LogicalORExpression:
                LogicalANDExpression:
                    BitwiseORExpression:
                        BitwiseXORExpression:
                            BitwiseANDExpression:
                                EuqalityExpression:
                                    RelationalExpression:
                                        ShiftExpressions:
                                            AdditiveExpression:
                                                MultiplicativeExpression:
                                                    UnaryExpression:
                                                        PostfixExpression:
                                                            LeftHandSideExpression:
                                                                NewExpression:
                                                                    MemberExpression:
                                                                        PrimaryExpression:

To answer the question

The curly brackets object notation specified as ObjectLiteral in ECMA-262 is by definition valid in every Expression except in case of an Expression which is derived from a Statement, as the ExpressionStatement explicitly prohibits the occurrence of an opening curly bracket as first character of an expression to resolve the conflict with the curly bracket code block (defined as Block). FunctionBody, Block, Program (global scope) and all loop constructs (IterationStatements) make use of statements and therefore have the restrictions to contain only Blocks and not ObjectLiterals in the code section.

Finally

The specification restricts curly brackets to represent either a code block or an object notation. The curly brackets are treated as a code block wherever the use of the 'var'-keyword is allowed and vice versa.