Ale*_*tin 28 javascript parsing operator-precedence
MDN声明 Javscript中有两个操作符具有最高优先级:
foo.barnew Foo()我通常明确地将两者分开:(new Date()).toString()
但我经常看到它们两者合二为一:new Date().toString()
根据这个答案,第二种方式起作用的原因在于,当两个运算符具有相同的优先级时,它是第二个运算符的关联性.在这种情况下,成员运算符是左关联的,这意味着new Date()首先评估.
但是,如果是这样的话,为什么会new Date.toString()失败呢?毕竟new Date是只是语法糖的new Date().上述论点说它应该有用,但显然不行.
我错过了什么?
geo*_*org 23
该语法是
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
Run Code Online (Sandbox Code Playgroud)
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 -> ()
Run Code Online (Sandbox Code Playgroud)
此外,直接在语法寻找神秘面纱的语法糖,轮流new Foo进入new Foo().这只是NewExpression←new NewExpression←new PrimaryExpression:
NewExpression :
MemberExpression
new NewExpression
Run Code Online (Sandbox Code Playgroud)
我是那个写了" 与不同关联性和相同优先级的邻近运算符消除表达式 "的问题和答案的人,当我写这篇文章时,我脑子里没有JavaScript.
我正在考虑的语言是Haskell,它是一种函数式编程语言.这些语言的操作员只是功能而且更容易推理.但是我以一种不假设任何编程语言的方式写了我的答案.
另一方面,JavaScript是一种传统的编程语言,JavaScript中的表达式基于精细的解析规则而消除歧义,这些规则与Haskell使用的解析规则非常不同.
特别是JavaScript解析规则似乎很贪婪.例如,举个例子:
new Date().toString()
Run Code Online (Sandbox Code Playgroud)
这里是函数调用后Date屏蔽Date成员操作符.因此new,贪婪,仍然只能操作Date而不是Date().toString.因此我们有:
((new Date()).toString)()
Run Code Online (Sandbox Code Playgroud)
在第二个例子中,我们有:
new Date.toString()
Run Code Online (Sandbox Code Playgroud)
这里没有函数调用Date来保护它免受成员操作符的影响.因此new,贪婪,操作表达Date.toString.因此我们有:
(new (Date.toString))()
Run Code Online (Sandbox Code Playgroud)
@ thg435的回答支持了这一主张.关键是我正在讨论一个与JavaScript解析器实现的完全不同的正式系统.我正在讨论的正式系统将运算符和操作数都视为一等值.