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?
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 einExpression
sein kann. _1 Beschränken Sie den dritten Ausdruck jedoch aufConditionalExpression
. 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.
Diese Antwort ist als Erweiterung der Antwort von Li357 gedacht. Speziell zu zeigen, wo der Bedingte Operator in der Grammatik PrimaryExpression
s zulässt (der den Comma-Operator nicht enthält), nicht aber Expression
s (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 AssignmentExpression
s. 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 .