Почему "new Date(). ToString()" работает с приоритетом Javascript-оператора?
MDN утверждает, что в Javscript есть два оператора, которые имеют самый высокий приоритет:
- Лево-ассоциативный оператор-член:
foo.bar
- Право-ассоциативный новый оператор:
new Foo()
Я обычно явно разделяю два: (new Date()).toString()
Но я часто вижу, что оба они объединены: new Date().toString()
В соответствии с этим ответом причина, по которой работает второй способ, заключается в том, что вторая операторная ассоциативность имеет значение, когда оба оператора имеют одинаковый приоритет. В этом случае оператор-член остается ассоциативным, что означает, что new Date()
оценивается первым.
Однако, если это так, то почему new Date.toString()
терпит неудачу? В конце концов, new Date
просто синтаксический сахар для new Date()
. В приведенном выше аргументе говорится, что он должен работать, но, очевидно, этого не делает.
Что мне не хватает?
Ответы
Ответ 1
Синтаксис
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 ← новое NewExpression ← новое PrimaryExpression:
NewExpression :
MemberExpression
new NewExpression
Ответ 2
Я тот парень, который написал как вопрос, так и ответ "Разнообразие выражений с соседними операторами различной ассоциативности и того же приоритета", и когда я написал что у меня не было 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. Формальная система, которую я обсуждал, обрабатывает операторы и операнды как значения первого класса.