34

MDN 声明Javscript 中有两个运算符具有最高优先级:

  • 左结合成员运算符:foo.bar
  • 右结合 new 运算符:new Foo()

我通常明确地将两者分开:(new Date()).toString()
但我经常看到它们结合在一起:new Date().toString()

根据这个答案,第二种方式起作用的原因是,当两个运算符具有相同的优先级时,第二个运算符的关联性很重要。在这种情况下,成员运算符是左关联的,这意味着new Date()首先评估。

但是,如果是这样,那为什么会new Date.toString()失败呢?毕竟,new Date只是. _ new Date()上面的论点说它应该起作用,但显然没有。

我错过了什么?

4

2 回答 2

25

语法是_

MemberExpression :
    PrimaryExpression
    FunctionExpression
    MemberExpression [ Expression ]
    MemberExpression . IdentifierName
    new MemberExpression Arguments

new foo().bar不能被解析为new (foo().bar)因为foo().bar不是 MemberExpression。此外,由于同样的原因,new foo()不能被解析为。new (foo())相反,new foo.bar 解析为new (foo.bar)因为foo.bar是一个有效的 MemberExpression(解释(new foo).bar是不可能的,因为语法是贪婪的)。

也就是说,优先规则是:dot beats new,new beats call (parens)。

.  -> new -> ()

此外,直接查看语法可以揭开new Foo变成new Foo(). 它只是 NewExpression ← new NewExpression ← new PrimaryExpression:

NewExpression :
    MemberExpression
    new NewExpression
于 2013-07-11T07:52:43.673 回答
7

我是写“用不同关联性和相同优先级的相邻运算符消除表达式的歧义”的问题和答案的人,当我写的时候我脑子里没有 JavaScript。

我考虑的语言是 Haskell,它是一种函数式编程语言。这种语言中的运算符只是简单的函数,并且更容易推理。但是,我以不采用任何编程语言的方式编写了答案。

另一方面,JavaScript 是一种传统的编程语言,JavaScript 中的表达式是基于复杂的解析规则来消除歧义的,这些规则与 Haskell 使用的解析规则非常不同。

特别是 JavaScript 解析规则似乎很贪婪。例如,以您的第一个示例为例:

new Date().toString()

这里的函数调用Date屏蔽Date了成员运算符。因此new,贪婪,仍然只能操作Date而不是Date().toString。因此我们有:

((new Date()).toString)()

在第二个示例中,我们有:

new Date.toString()

这里没有函数调用Date来保护它免受成员运算符的影响。因此new,贪婪,对表达式进行操作Date.toString。因此我们有:

(new (Date.toString))()

@thg435 的回答支持了这一说法。重点是我在讨论一个与 JavaScript 解析器实现的完全不同的正式系统。我正在讨论的正式系统将运算符和操作数都视为一等值。

于 2013-07-11T09:02:41.187 回答