这个JavaScript表达式是如何解释的?

nuypyhwy  于 2023-10-14  发布在  Java
关注(0)|答案(2)|浏览(82)

如何解析和解释以下表达式?
Chrome控制台是这样做的:

> {'foo'}{'bar'}
'bar'

并且类似地

> {a: 'foo'}{b: 'bar'}
'bar'

(显然,这里发生的任何事情都不应该在真实的代码中使用。)

soat7uwm

soat7uwm1#

您可以使用AST Explorer查看AST详细信息。
代码1:

{'foo'}{'bar'}

AST:

[
  {
    "type": "BlockStatement",
    "start": 0,
    "end": 7,
    "body": [
      {
        "type": "ExpressionStatement",
        "start": 1,
        "end": 6,
        "expression": {
          "type": "Literal",
          "start": 1,
          "end": 6,
          "value": "foo",
          "raw": "'foo'"
        }
      }
    ]
  },
  {
    "type": "BlockStatement",
    "start": 7,
    "end": 14,
    "body": [
      {
        "type": "ExpressionStatement",
        "start": 8,
        "end": 13,
        "expression": {
          "type": "Literal",
          "start": 8,
          "end": 13,
          "value": "bar",
          "raw": "'bar'"
        }
      }
    ]
  }
]

也就是说两个街区
代码2:

{a: 'foo'}{b: 'bar'}

AST:

[
  {
    "type": "BlockStatement",
    "start": 0,
    "end": 10,
    "body": [
      {
        "type": "LabeledStatement",
        "start": 1,
        "end": 9,
        "body": {
          "type": "ExpressionStatement",
          "start": 4,
          "end": 9,
          "expression": {
            "type": "Literal",
            "start": 4,
            "end": 9,
            "value": "foo",
            "raw": "'foo'"
          }
        },
        "label": {
          "type": "Identifier",
          "start": 1,
          "end": 2,
          "name": "a"
        }
      }
    ]
  },
  {
    "type": "BlockStatement",
    "start": 10,
    "end": 20,
    "body": [
      {
        "type": "LabeledStatement",
        "start": 11,
        "end": 19,
        "body": {
          "type": "ExpressionStatement",
          "start": 14,
          "end": 19,
          "expression": {
            "type": "Literal",
            "start": 14,
            "end": 19,
            "value": "bar",
            "raw": "'bar'"
          }
        },
        "label": {
          "type": "Identifier",
          "start": 11,
          "end": 12,
          "name": "b"
        }
      }
    ]
  }
]

所以这意味着两个块有两个labels

t98cgbkg

t98cgbkg2#

第一个语句可以重写为

{
  'foo';
}
{
  'bar';
}

也就是说,两个单独的块语句,每个语句都包含一个常量字符串。结果是解释此代码时计算的最后一个表达式,即'bar'
第二个语句可以类似地重写为

{
  a: 'foo';
}
{
  b: 'bar';
}

其中ablabels,可用于代码中的有限跳转(通常用于退出嵌套循环中的内部循环)。同样,它的值为'bar'。虽然第二个语句看起来有点类似于对象字面量,但事实并非如此。请注意,> {b: 'bar', a: 'foo'}会导致语法错误:
未捕获的语法错误:意外令牌:':'
正如Pointy在注解中所观察到的,当解释器遇到一个以{开头的语句时,它可能属于一个对象文字或一个代码块,它会一致地将其解释为一个代码块。所有符合规范的解析器都是这样吗?让我们假设js grammar contributed to Antlr4是正确的(根据评论,它是为ES 2020更新的)。在Antlr 4中,任何先指定的规则都优先于后面的规则。我们发现(从链接的语法中复制并粘贴相关规则):

program
    : HashBangLine? sourceElements? EOF
    ;

sourceElement
    : statement
    ;

statement
    : block
    | variableStatement
    | importStatement
    | exportStatement
    | emptyStatement_
    | classDeclaration
    | functionDeclaration
    | expressionStatement
    | ifStatement
    | iterationStatement
    | continueStatement
    | breakStatement
    | returnStatement
    | yieldStatement
    | withStatement
    | labelledStatement
    | switchStatement
    | throwStatement
    | tryStatement
    | debuggerStatement
    ;

expressionStatement
    : {this.notOpenBraceAndNotFunction()}? expressionSequence eos
    ;

expressionSequence
    : singleExpression (',' singleExpression)*
    ;

singleExpression
# ...snipped many lines...
    | objectLiteral                # ObjectLiteralExpression
    | '(' expressionSequence ')'   # ParenthesizedExpression
    ;

因此,假设这个语法是正确的,JS将总是将打开的{ s解释为块,因为blockstatement中出现的时间比expressionStatement早得多(这导致objectLiteral通过expressionSequences-> singleExpression-> objectLiteral)。

相关问题