34

MDN は、最も高い優先順位を共有する JavaScript には 2 つの演算子があると述べています。

  • 左結合メンバー演算子:foo.bar
  • 右結合 new 演算子:new Foo()

私は通常、この 2 つを明確に分けてい(new Date()).toString()
ます。new Date().toString()

この答えによると、2番目の方法が機能する理由は、両方の演算子の優先順位が等しい場合に重要になるのは2番目の演算子の結合性だからです。この場合、メンバー演算子は結合されたままになります。つまり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は MemberExpression ではないnew (foo().bar)ため、解析できません。foo().barまた、同じ理由でnew foo()として解析できません。new (foo())逆に、new foo.bar new (foo.bar)有効なMemberExpressionであると解析されfoo.barます (文法が貪欲であるため、解釈(new foo).barは不可能です)。

つまり、優先順位のルールは次のとおりです。

.  -> 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)()

2 番目の例では、次のようになります。

new Date.toString()

ここでDateは、メンバー演算子からシールドするための関数呼び出しはありません。したがってnew、貪欲であることは、式に作用しますDate.toString。したがって、次のようになります。

(new (Date.toString))()

@ thg435 の回答は、この主張を裏付けています。要点は、JavaScript パーサーによって実装されるものとはまったく異なる正式なシステムについて議論していたということです。私が議論していた正式なシステムは、演算子とオペランドの両方を第一級の値として扱います。

于 2013-07-11T09:02:41.187 に答える