web-dev-qa-db-de.com

Warum löst dieses Komma in einem ternären Operator einen Syntaxfehler in JavaScript aus?

Beim Versuch, den Komma-Operator innerhalb des bedingten (ternären) Operators für die Protokollierung zu verwenden, ist mir etwas Merkwürdiges aufgefallen. Hier ist ein ausgedachtes Beispiel:

const a = 2;
const b = 1;
a > b ? console.log(a), a : b; //I expect this to log and evaluate to a

Aber stattdessen bin ich auf folgendes gestoßen:

Uncaught SyntaxError: Unexpected token ,

Gemäß der MDN-Dokumentation akzeptiert der bedingte Operator zwei Ausdrücke als 'if'- und' else'-Fälle des ternären Operators, und der Komma-Operator theoretisch ist ein Ausdruck as ,

Der Kommaoperator wertet jeden seiner Operanden aus (von links nach rechts) und gibt den Wert des letzten Operanden zurück.

Warum erhalte ich einen Syntaxfehler? Der Komma-Operator ist ein Ausdruck, der sich in einem bedingten Operator befinden darf. Das Setzen von Klammern um die Komma-Operanden funktioniert jedoch einwandfrei:

a > b ? (console.log(a), a) : b; //Logs and gives a

Warum funktioniert das gut? Klammern (oder der Gruppierungsoperator ) ermöglichen es dem Interpreter, zu wissen dass es sich um einen Ausdruck handelt, aber console.log(a), a ist bereits ein Ausdruck ohne Klammern. Warum also? Ohne sie einen Syntaxfehler bekommen?

23
Li357

Dies ist ein absichtlicher Teil der Sprache und wird in der ECMAScript-Sprachspezifikation beschrieben. Die Syntax für den Kommaoperator ist in Abschnitt 12.16 definiert, in dem Folgendes angegeben ist:

12.16 Kommaoperator (,)

Syntax

Ausdruck:AssignmentExpressionAusdruck, AssignmentExpression

In der Spezifikation wird beschrieben, wie der Kommaoperator verwendet wird. Ein Expression ist ein beliebiges AssignmentExpression oder sich selbst, gefolgt von einem Komma (dem Operator) und einem anderen AssignmentExpression. Zu beachten ist, dass ein AssignmentExpression ein Expression ist, aber ein Expression ist nicht und ein AssignmentExpression.

Die Grammatik für den Operator und die bedingten Ausdrücke ist für den tatsächlichen bedingten Operator in Abschnitt 12.14 spezifiziert:

12.14 Bedingter Operator (?:)

Syntax

ConditionalExpression: 
 LogicalORExpressionLogicalORExpression? AssignmentExpression: AssignmentExpression

Gemäß der Spezifikation kann ein bedingter Ausdruck nur AssignmentExpression s enthalten - nicht nur Expression s. Daher kann ein Bedingungsoperator keinen Kommaoperator in einem seiner Operanden haben. Das mag wie eine seltsame Sprache aussehen, aber es gibt einen bestimmten Grund, wenn man die sehr spezifische Grammatik und die Spezifikation bedenkt:

HINWEIS Die Grammatik für ein ConditionalExpression in ECMAScript unterscheidet sich geringfügig von der in C und Java , wodurch jeweils der zweite Unterausdruck ein Expressionsein kann. _1 Beschränken Sie den dritten Ausdruck jedoch auf ConditionalExpression . Der Grund für diesen Unterschied in ECMAScript besteht darin, zuzulassen, dass ein Zuweisungsausdruck von jedem Arm einer Bedingung und gesteuert wird, um den verwirrenden und ziemlich nutzlosen Fall eines Kommaausdrucks als Mittelpunktausdruck zu beseitigen.

Aufgrund der eingeschränkten Grammatik von Java und C lassen sie Folgendes nicht zu (Java):

int a = 2;
int b = 1;
System.out.println(a > b ? b = a : a = b); //Can't use assignment in 'else' part
//                                 ^^^^^

ECMAScript-Autoren beschlossen, die Zuordnung in beiden Zweigen des ternären Operators zuzulassen, sodass diese Definition mit AssignmentExpression erfolgte. Folglich verhindert diese Definition auch, dass der Kommaoperator tatsächlich im "Wenn" -Teil des Bedingungsoperators angezeigt wird, aber aufgrund seiner Knappheit und Nutzlosigkeit war dies kein Problem. Sie töteten im Wesentlichen zwei Fliegen mit einer Klappe; für weniger nachgiebige Grammatik zugelassen und nutzlose Syntax, die schlechte Praxis ist, entfernt.

Der Grund, warum das Hinzufügen des Gruppierungsoperators es zulässt, dass es funktioniert, liegt darin, dass der Gruppierungsoperator production ( Expression ) per Definition auch ein AssignmentExpression ist, der es dem ternären Operator ermöglicht, siehe Antwort von str für mehr Details.


1 Dies bezieht sich auf Javas Expression, nicht auf ECMAScript's Expression. Java hat not nicht den Kommaoperator, so dass Expression ihn nicht enthält.

29
Li357

Diese Antwort ist als Erweiterung der Antwort von Li357 gedacht. Speziell zu zeigen, wo der Bedingte Operator in der Grammatik PrimaryExpressions zulässt (der den Comma-Operator nicht enthält), nicht aber Expressions (der den Comma-Operator enthält).


Bitte sehen Sie sich die Links zu den Spezifikationen für alle genannten Ausdruckstypen oder Operatoren unten in dieser Antwort an.

Die Spezifikation des Bedingungsoperators ist wie folgt definiert: 

ConditionalExpression:
  LogicalORExpression
  LogicalORExpression ? AssignmentExpression : AssignmentExpression

Somit kann es entweder nur eine LogicalORExpression sein oder eine Kombination aus LogicalORExpression und zwei AssignmentExpressions. Eine AssignmentExpression selbst kann unter anderem auch durch eine LogicalORExpression angegeben werden.

Anders als der einfach klingende Name ist LogicalORExpression nicht nur eine Grundbedingung, sondern kann aus vielen, vielen verschachtelten Ausdrücken selbst bestehen. Bis hin zu PrimaryExpression, zu dem auch gruppierte Ausdrücke (Expression) gehören.

Und wie in der Spezifikation des Comma-Operators zu sehen ist, wird er nur in Expression angegeben, aber nicht in PrimaryExpression selbst.

Expression:
  AssignmentExpression
  Expression , AssignmentExpression

Um es in einfacheren Worten zusammenzufassen: Die Grammatik von JavaScript lässt den Kommaoperator nur innerhalb einer AssignmentExpression zu, wenn er innerhalb eines Gruppierungsoperators () enthalten ist.

Siehe auch den Operator-Vorrang in JavaScript .

Ressourcen

1
str