【问题标题】:CallExpression vs NewExpression in ECMAScript 2017ECMAScript 2017 中的 CallExpression 与 NewExpression
【发布时间】:2018-08-02 15:49:23
【问题描述】:

根据this SO postCallExpression 始终包含一个调用,因此不能成为new 运算符之后的表达式的一部分。

但是,ECMAScript 2017 表示:

MemberExpression:
   PrimaryExpression
   MemberExpression [Expression]
   MemberExpression .IdentifierName
   MemberExpression TemplateLiteral
   SuperProperty
   MetaProperty
   new MemberExpression Arguments

还有:

NewExpression:
   MemberExpression
   new NewExpression

还有:

CallExpression:
   CoverCallExpressionAndAsyncArrowHead
   SuperCall
   CallExpression Arguments
   CallExpression [Expression]
   CallExpression .IdentifierName
   CallExpression TemplateLiteral

还有:

CoverCallExpressionAndAsyncArrowHead:
   MemberExpression Arguments

问题

  1. 为什么MemberExpression Arguments 生产位于14.7 Async Arrow Function Definitions 部分? Cover 是否意味着该规则同时涵盖CallExpressionAsyncArrowHead,而他们只是决定将其放入14.7 而不是12.3
  2. 根据上述产品,以下内容将是有效的,因此与上面链接的 SO 帖子不同。我错过了什么吗?既然NewExpression可以包含CallExpression,为什么还要分NewExpressionCallExpression呢?

显然有效:

new new memberExpression(args);

这是new new MemberExpression Arguments,与第一个CallExpression生产相同。

【问题讨论】:

  • 我不明白你的第二个问题。你能改写一下吗? new new memberExpression(args); 在任何地方都不会被 CallExpression 解析。
  • 嗨@bergi。我的意思是new MemberExpression Arguments 实际上是一个有效的NewExpression,它也遵循与CallExpression 相同的结构:const foo = new Bar()。注意最后的括号。我猜是因为括号是可选的,正如洛根指出的那样。
  • 好吧,Bar() 部分的结构可能在 MemberExpression/NewExpressionCallExpression 之间是相同的,但是因为前面有一个 new,所以整个事情不是CallExpression

标签: javascript ecmascript-6 ecmascript-2017


【解决方案1】:

为什么 MemberExpression Arguments 产生式位于第 14.7 节异步箭头函数定义中? Cover 是否意味着该规则同时涵盖 CallExpression 和 AsyncArrowHead,而他们只是决定将其放入 14.7 而不是 12.3?

这是因为async 不是关键字。这意味着在解析器中

async ()

只是对名为async 的函数的函数调用。这意味着在类似 sn-p 的上下文中

async () =>

在找到=> 之前,解析器无法知道它实际解析的是什么类型的语法。这个概念是一组已知的标记,具有多种可能的输出 AST 结构,在规范中通过所谓的覆盖语法处理。

在规范的一般情况下,这实质上意味着CoverCallExpressionAndAsyncArrowHead 本质上定义了您可以在箭头函数头或函数调用中找到的可能结构的联合。当解析器看到=> 时,它会说“好的,我解析的CoverCallExpressionAndAsyncArrowHead 是箭头函数的头部,如果它找到=> 以外的任何东西,那么它就知道它实际上是一个函数调用。

根据上述制作,以下内容将是有效的,因此与上面链接的 SO 帖子不同。我错过了什么吗?既然NewExpression可以包含CallExpression,为什么要分NewExpression和CallExpression呢?

我还发现其他答案中的措辞有点难以理解,尽管我认为它是准确的。简短的回答是,然后将其分成NewExpressionCallExpression,因为CallExpression 需要 括号,而NewExpression 需要 是括号。例如,一般意义上的new 是一个关键字,它构造右侧的任何内容。如果你做new Foo,它将构造Foo。如果您执行new obj.Foo,它将读取obj.Foo,然后从中构造一个对象。这意味着在语法上您几乎可以将它们视为等价的:

// 1
var _tmp = Foo;
new _tmp;

// 2
var _tmp = obj.Foo;
new _tmp;

但这不是真的,因为它们是不同的:

// 3
var _tmp = Foo();
new _tmp;

// 4
new Foo();

new 关键字有可选括号,正是这种行为需要语法中的除法。如果我们看

NewExpression:
  MemberExpression
  new NewExpression

它总是直接跳转到MemberExpression,这意味着new obj() 会将() 视为Arguments 中的new MemberExpression Arguments。由于CallExpression 总是处理函数调用的(),所以NewExpression 语法仅适用于构造可选的(),而

CallExpression:
  CoverCallExpressionAndAsyncArrowHead
  SuperCall
  CallExpression Arguments
  CallExpression [Expression]
  CallExpression .IdentifierName
  CallExpression TemplateLiteral

处理所有涉及没有new的函数调用的()案例。

【讨论】:

  • 非常感谢洛根。快速澄清:您的意思是在new obj() 中,obj() 被视为new MemberExpression Arguments(不仅仅是() 部分)?这是我应用的语法替换:NewExpression: new NewExpression --> new MemberExpression --> new new MemberExpression Arguments。或者:NewExpression: MemberExpression --> new MemberExpression Arguments
  • 另一件我有点不清楚的事情:Left-Hand-Side Expression 到底是什么,如果它不是应该位于运算符左侧的那个(比如在一个任务)?显然,如果 LeftHandSideExpressionReference 类型,则分配仅适用于 LeftHandSideExpression
  • 哦,是的,我的意思是() 会触发new MemberExpression Argument 语法的使用。 “这是我应用的语法替换”我不确定我是否遵循这些示例。一个有一个 new 关键字,一个有两个关键字,所以这里只有 NewExpression: MemberExpression --> new MemberExpression Arguments 可用。
  • 我通常认为左侧表达式本质上是可以分配的任何东西。该行为以嵌套方式定义,因为在您真正到达 = 之前它不知道某物是否是左手,所以在此之前它可能只是左手,也可能不是。
  • 关于什么是 LHS 表达式,以下 SO 帖子强调了一些有趣的事情:stackoverflow.com/questions/3709866/…new Object 是一个有效的LeftHandSideExpression,但是不能赋值给它(显然是因为它不是Reference 类型)?
猜你喜欢
  • 2018-09-13
  • 1970-01-01
  • 2018-07-20
  • 2018-02-11
  • 2018-09-11
  • 2018-06-06
  • 1970-01-01
  • 2013-10-09
  • 2015-08-28
相关资源
最近更新 更多