Why does “new Date().toString()” work given Javascript operator precedence?

心已入冬 提交于 2019-11-30 02:57:40

The syntax is

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

new foo().bar cannot be parsed as new (foo().bar) because foo().bar is not a MemberExpression. Moreover, new foo() cannot be parsed as new (foo()), for the same reason. Conversely, new foo.bar is parsed as new (foo.bar) because foo.bar is a valid MemberExpression (an interpretation (new foo).bar is impossible because the grammar is greedy).

That is, the precedence rule is: dot beats new, new beats call (parens).

.  -> new -> ()

Furthermore, looking directly at the grammar demystifies the syntactic sugar that turns new Foo into new Foo(). It's simply NewExpression ← new NewExpression ← new PrimaryExpression:

NewExpression :
    MemberExpression
    new NewExpression
Aadit M Shah

I'm the guy who wrote both the question and the answer of "Disambiguation of expressions with neighboring operators of different associativity and same precedence", and when I wrote that I didn't have JavaScript in my mind.

The language I was considering was Haskell, which is a functional programming language. Operators in such languages are simply functions and are much easier to reason about. However I wrote my answer in a manner which didn't assume any programming language.

On the other hand JavaScript is a traditional programming language and expressions in JavaScript are disambiguated based on elaborate parsing rules which are very different from the parsing rules employed by Haskell.

In particular JavaScript parsing rules seem to be greedy. For example take your first example:

new Date().toString()

Here the function call after Date shields Date from the member operator. Hence new, being greedy, can still only operate on Date instead of Date().toString. Hence we have:

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

In the second example we have:

new Date.toString()

Here there's no function call after Date to shield it from the member operator. Hence new, being greedy, operates on the expression Date.toString. Hence we have:

(new (Date.toString))()

@thg435's answer backs up this claim. The point is that I was discussing a formal system which is totally different from the one implemented by JavaScript parsers. The formal system I was discussing treats operators and operands both as first class values.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!