Precedencia de operadores con el operador ternario de JavaScript

7 minutos de lectura

avatar de usuario
Baijs

Parece que no puedo entender la primera parte de este código ( += ) en combinación con el operador ternario.

h.className += h.className ? ' error' : 'error'

La forma en que creo que funciona este código es la siguiente:

h.className = h.className + h.className ? ' error' : 'error'

Pero eso no es correcto, porque da un error en mi consola.

¿Cómo debo interpretar este código correctamente?

avatar de usuario
kobi

Usar:

h.className = h.className + (h.className ? ' error' : 'error')

Quiere que el operador trabaje para h.className. Mejor ser específico al respecto.

Por supuesto, ningún daño debe venir de h.className += ' error'pero eso es otra cosa.

Además, tenga en cuenta que + tiene precedencia sobre el operador ternario: Precedencia de operadores de JavaScript

  • Creo que se debe tener en cuenta que, si bien ningún daño debería h.className += ' error', también deja un espacio en blanco al principio de la cadena si inicialmente estaba vacía. Creo que el objetivo de la operación ternaria es producir una cadena de aspecto limpio.

    – JMTyler

    21 de junio de 2011 a las 22:15

  • @JMTyler: eso es exactamente lo que estaba indicando: si todo se hace solo para mantener un espacio desde el principio, no valgo la pena. (el caso de borde incluye selectores jQuery o XPath exactos). Gracias de todos modos.

    – Kobi

    22 de junio de 2011 a las 4:44

  • ¡@Kobi +1 solo por la advertencia de precedencia del operador!

    – Ed Capilla

    15 de agosto de 2012 a las 20:01

avatar de usuario
wayne koorts

Piénsalo de esta manera:

<variable> = <expression> ? <true clause> : <false clause>

La forma en que se ejecuta la declaración es básicamente la siguiente:

  1. Lo hace <expression> evalúa a verdadero, o se evalúa a falso?
  2. Si <expression> se evalúa como verdadero, entonces el valor de <true clause> se asigna a <variable>, <false clause> se ignora y se ejecuta la siguiente sentencia.
  3. Si <expression> se evalúa como falso, entonces <true clause> se ignora y el valor de <false clause> se asigna a <variable>.

Lo importante a tener en cuenta con el operador ternario en este y otros lenguajes es que cualquier código que esté en <expression> debe producir un resultado booleano cuando se evalúa: ya sea verdadero o falso.

En el caso de su ejemplo, reemplace “asignado a” en mi explicación con “agregado a”, o similar para cualquier aritmética abreviada que esté usando, si corresponde.

  • Tenga en cuenta si el Perfecto comentario es apropiado 🙂 Se salta cualquier explicación de por qué las expresiones de la izquierda “agrupadas” primero (es decir, porque + tiene mayor precedencia que el operador condicional/ternario (de hecho, el operador condicional es casi siempre el último evaluado en cualquier expresión).

    – Codificación pasada

    11 de junio de 2014 a las 14:24


los += hace lo que quiere, pero en la declaración ternaria a la derecha, verifica si h.className es falsey, que sería si no estuviera definido. Si es cierto (es decir, si ya se especificó un nombre de clase), entonces se agrega el error con un espacio (es decir, se agrega un nuevo clase), de lo contrario, se agrega sin el espacio.

El código podría reescribirse como sugiere, pero debe especificar que h.className se usará para la comparación de veracidad, en lugar de usar su valor real, en el operador ternario, así que asegúrese de no molestarse con la concatenación de valores al mismo tiempo que realiza su operación ternaria:

h.className = h.className + (h.className ? ' error' : 'error');

  • bueno sí, undefined no es falso simplemente se trata como si fuera

    – David Hedlund

    24 de noviembre de 2009 a las 10:15

avatar de usuario
justin johnson

El lado derecho de la = El operador se evalúa de izquierda a derecha. Asi que,

g.className = h.className + h.className ? ' error' : 'error';`

es equivalente a

h.className = (h.className + h.className) ? ' error' : 'error';

Ser equivalente a

h.className += h.className ? ' error' : 'error';

tienes que separar la declaración ternaria entre paréntesis:

h.className = h.className + (h.className ? ' error' : 'error');

if (h.className) {
    h.className = h.className + ' error';
} else {
    h.className = h.className + 'error';
}

debe ser equivalente a:

h.className += h.className ? ' error' : 'error';

avatar de usuario
Pedro Mortensen

Me gustaría elegir la explicación de Wayne:

<variable> = <expression> ? <true clause> : <false clause>

Consideremos ambos casos:

Caso 1

h.className += h.className ? 'true' : 'false'
  • el operador de asignación funciona bien y el valor se agrega
  • cuando se ejecuta por primera vez, la salida es falsa
  • Segunda vez. Salida: falsetrue: los valores se siguen agregando

Caso 2:

h.className = h.className + h.className ? 'true' : 'false'
  • el resultado no es el mismo que el caso 1
  • cuando se ejecuta por primera vez, la salida es falso
  • Segunda vez. Salida: falso: los valores no se siguen agregando

Explicación

En el código anterior, el caso 1 funciona bien

mientras

caso 2,

h.className = h.className + h.className ? 'true' : 'false'

se ejecuta como

 h.className = (h.className + h.className) ? 'true' : 'false'

h.className + h.className => considerado como una expresión para el operador ternario ya que el operador ternario tiene mayor prioridad. Entonces, siempre se asigna el resultado de la expresión ternaria.

h.className = h.className + (h.className ? ' error' : 'error')

avatar de usuario
Pedro Mortensen

Pero no estoy 100% satisfecho con ninguna de las respuestas, ya que todas parecen incompletas. Así que aquí vamos de nuevo desde los primeros principios:

El objetivo general del usuario:

Resumiendo el código: “Quiero agregar un error nombre de clase a una cadena, opcionalmente con un espacio inicial si ya hay nombres de clase en la cadena”.

La solución más simple

Como señaló Kobi, hace cinco años, tener un espacio inicial en los nombres de clase no causará ningún problema con ningún navegador conocido, por lo que la solución correcta más breve sería:

h.className += ' error';

Ese debería haber sido el respuesta real hacia problema real.


Sea como fuere, las preguntas que se hicieron fueron…

1. ¿Por qué funcionó esto?

h.className += h.className ? ' error' : 'error'

El operador condicional/ternario funciona como un si declaración, que asigna el resultado de su true o false caminos a una variable.

Entonces ese código funcionó porque se evalúa simplemente como:

if (h.className IS NOT null AND IS NOT undefined AND IS NOT '')
    h.className += ' error'
else
    h.className += 'error'

2. ¿Y por qué se rompió esto?

h.className = h.className + h.className ? ' error' : 'error'

La pregunta dice “eso da un[n] error en mi consola”, lo que puede inducirlo a pensar erróneamente que el código no funciona. De hecho, el siguiente código se ejecuta, sin errorpero simplemente devuelve ‘error’ si la cadena no estaba vacío y ‘error’ si la cadena estaba vacío y así no cumplía con los requisitos.

Ese código siempre da como resultado una cadena que contiene solo ' error' o 'error' porque se evalúa a este pseudocódigo:

if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
    h.className=" error"
else
    h.className="error"

La razón de esto es que el operador de suma (+ para la gente común) tiene mayor “precedencia” (6) que el operador condicional/ternario (15). Sé que los números aparecen al revés.

Precedencia simplemente significa que cada tipo de operador en un idioma se evalúa en un orden predefinido particular (y no solo de izquierda a derecha).

Referencia: Precedencia de operadores de JavaScript

Cómo cambiar el orden de evaluación:

Ahora sabemos por qué falla, necesita saber cómo hacer que funcione.

Algunas otras respuestas hablan de cambiando la precedenciapero no puedes. La precedencia está integrada en el lenguaje. Eso es solo un conjunto fijo de reglas… Sin embargo, puede cambiar el orden de evaluacion

La herramienta en nuestra caja de herramientas que puede cambiar el orden de evaluación es el operador de agrupación (también conocido como corchetes). Lo hace asegurándose de que las expresiones entre paréntesis se evalúen. antes de operaciones fuera de los corchetes. Eso es todo lo que hacen, pero eso es suficiente.

Los corchetes funcionan simplemente porque (los operadores de agrupación) tienen precedencia más alta que todos los demás operadores (“ahora hay un nivel 0”).

Simplemente agregando corchetes usted cambiar el orden de evaluación para garantizar que la prueba condicional se realice primero, antes de la concatenación de cadenas simple:

h.className = h.className + (h.className ? ' error' : 'error')

¿Ha sido útil esta solución?