ternarios - ¿Por qué esta coma dentro de un operador ternario arroja un error de sintaxis en JavaScript?
operadores ternarios php (2)
Noté algo extraño al tratar de usar el operador de coma dentro del operador condicional (ternario) para el registro. Aquí hay un ejemplo artificial:
const a = 2;
const b = 1;
a > b ? console.log(a), a : b; //I expect this to log and evaluate to a
Pero en cambio me encuentro con esto:
Uncaught SyntaxError: Unexpected token ,
De acuerdo con la documentación de MDN , el operador condicional acepta dos expresiones como los casos "if" y "else" del operador ternario, y el operador de coma en teoría es una expresión como,
El operador de coma evalúa cada uno de sus operandos (de izquierda a derecha) y devuelve el valor del último operando.
Entonces, ¿por qué recibo un error de sintaxis? El operador de coma es una expresión que debe permitirse estar en un operador condicional. Aunque, poner paréntesis alrededor de los operandos de la coma funciona bien:
a > b ? (console.log(a), a) : b; //Logs and gives a
¿Por qué funciona bien? Los paréntesis (o el operador de agrupación ) le permiten al intérprete saber que se trata de una expresión, pero console.log(a), a
ya es una expresión sin la necesidad de paréntesis, así que ¿por qué me aparece un error de sintaxis sin ellos?
Esta es una parte intencional del idioma y se describe en la Especificación de lenguaje ECMAScript . La sintaxis para el operador de coma se define en la Sección 12.16 , que establece lo siguiente:
12.16 Operador de coma (,)
Sintaxis
Expression: AssignmentExpression Expression, AssignmentExpression
Aquí, la especificación describe cómo se usa el operador de coma. Una Expression
es cualquier AssignmentExpression
o ella misma seguida de una coma (el operador) y otra AssignmentExpression
. Lo importante a tener en cuenta es que una Expression
AssignmentExpression
es una Expression
pero una Expression
no es una Expression
AssignmentExpression
.
En cuanto al operador condicional real, la gramática para el operador y las expresiones condicionales se especifica en la Sección 12.14 :
12.14 Operador Condicional (?:)
Sintaxis
ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression
Según la especificación, una expresión condicional solo puede contener AssignmentExpression
s, no solo Expression
s. Por lo tanto, un operador condicional no puede tener un operador de coma dentro de uno de sus operandos. Esto puede parecer una extraña peculiaridad del lenguaje, pero hay una razón específica que considera la gramática muy específica, y por la especificación:
NOTA La gramática para una expresión
ConditionalExpression
en ECMAScript es ligeramente diferente de la de C y Java , cada una de las cuales permite que la segunda subexpresión sea unaExpression
1, pero restringe la tercera expresión para ser una expresión Java . La motivación para esta diferencia en ECMAScript es permitir que una expresión de asignación sea gobernada por cualquiera de los brazos de un condicional y eliminar el caso confuso y bastante inútil de una expresión de coma como la expresión central.
Debido a la gramática restrictiva de Java y C, no permiten cosas como esta (Java):
int a = 2;
int b = 1;
System.out.println(a > b ? b = a : a = b); //Can''t use assignment in ''else'' part
// ^^^^^
Los autores de ECMAScript decidieron permitir la asignación en ambas ramas del operador ternario, por lo que se produjo esta definición con AssignmentExpression
. En consecuencia, esta definición tampoco permite que el operador de coma aparezca realmente en la parte "si" del operador condicional, pero debido a su escasez e inutilidad no fue un problema. Esencialmente mataron a dos pájaros de un tiro; permitió una gramática más indulgente y eliminó una sintaxis inútil que es una mala práctica.
La razón por la que agregar el operador de agrupación le permite trabajar es porque la producción del operador de agrupación ( Expression )
es, por definición, también una ( Expression )
AssignmentExpression
permite que esté en el operador ternario; consulte la respuesta de str para obtener más detalles.
1 Esto se refiere a la Expression
de Java , no a la Expression
de ECMAScript. Java no tiene el operador de coma, por lo que su Expression
no lo incluye.
Esta respuesta es una extensión de la respuesta de Li357 . Específicamente para mostrar en qué parte de la gramática el Operador Condicional permite la PrimaryExpression
s (que no incluye el Operador de Coma) pero no la Expression
s (que incluye el Operador de Coma).
Consulte los enlaces a la especificación para cada tipo de expresión u operador mencionado al final de esta respuesta.
La especificación del operador condicional se define de la siguiente manera:
ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression
Por lo tanto, puede ser solo una LogicalORExpression
o una combinación de LogicalORExpression
y dos LogicalORExpression
AssignmentExpression
. Una propia AssignmentExpression
puede, entre otras cosas, ser especificada por una LogicalORExpression
también.
Pero, a diferencia de su nombre que suena simple, LogicalORExpression
no es solo una condición básica, sino que puede constar de muchas, muchas expresiones anidadas diferentes. Hasta la PrimaryExpression
que también incluye expresiones agrupadas (Expression)
.
Y como se puede ver en la especificación del operador de coma, solo se especifica en la Expression
, pero no en la PrimaryExpression
en sí.
Expression: AssignmentExpression Expression , AssignmentExpression
Para resumirlo en palabras más simples: la gramática de JavaScript solo permite al operador de coma dentro de una AssignmentExpression
si está contenido dentro de un operador de agrupación ()
.
También vea la precedencia del operador en JavaScript .