Operador ternario en Javascript: modelo largo y su rendimiento comparado

01 Abr 2011

El operador ternario es un condicional simple que ejecuta una de dos instrucciones posibles dependiendo de la evaluación previa de una condición.

Su sintaxis es la siguiente:

condition ? instructionIfTrue : instructionIfFalse;

Donde:

condition es una expresión de tipo Booleana.
instructionIfTrue es la expresión que se ejecuta si condition es igual a true.
instructionIfFalse es la expresión que se ejecuta si condition es igual a false.

Su uso suele asociarse a la asignación del valor para una variable que depende de alguna condición:

var status = ( user.name && user.pass ) ? 'Logged' : 'Unlogged';

Básicamente, se trata de una forma abreviada de una instrucción if … else.

Estructura larga del operador ternario

Si nos encontramos cómodos utilizando este operador, podemos ir más allá de su definición y crear estructuras largas que ejecuten varias acciones distintas dependiendo de una serie de condiciones.

Revisemos el siguiente código:

var a = 11;
var numberLiteral = a == 5 ? 'Five' :
                    a == 7 ? 'Seven' :
                    a == 11 ? 'Eleven' :
                    a == 15 ? 'Fifteen' :
                    'Other Number';
 
console.log( numberLiteral ); // Eleven

Con esta estructura establecemos una serie de valores según el resultado del condicional como si fuera una clásica estructura if … else u otra de tipo switch. El resultado es un bloque muy legible y sencillo de mantener.

Si medimos el rendimiento de cada una de estas posibilidades, obtendremos la siguiente tabla:

Performance Ternary vs If vs SwitchLos datos son, como siempre, interesantes:

– En Chrome, el método más rápido es el switch.
– En Firefox 4, el ternario y el if…else andan parejos, pero el switch es 15 veces más lento!
– En Internet Explorer, todos los métodos tienen un rendimiento similar: bajo.
– En Opera, el ternario es ligeramente más lento, pero todos mantienen un buen rendimiento.

El test puede consultarse de forma online aquí.

Jugando con el operador ternario

Para las asignaciones booleanas de tipo true – false, podemos emular la estructura ternaria con la asignación por igualdad. Por ejemplo, el siguiente código

var language = 'Javascript';
var dynamic = ( language === "Javascript" ) ? true : false;
 
console.log( dynamic ); // true

puede reescribirse como:

var language = 'Javascript';
var dynamic = language === 'Javascript';
 
console.log( dynamic ); // true

Curiosamente, si medimos el rendimiento de ambas estructuras encontramos que, según el navegador testeado, una puede ser más rápida que otra pero siempre se mantienen muy cerca.

Podemos ver el análisis comparativo realizado en JSPerf aquí.

Conclusión

El operador ternario es una estructura condicional muy interesante que permite ahorrarnos unos cuantos caracteres a la hora de asignar un determinado valor según una condición previa.

El test de rendimiento nos demuestra que se defiende dignamente frente a otras estructuras como son los bloques if…else o switch. Su elección dependerá finalmente de nuestro propio criterio y de lo cómodos que nos encontremos frente a su uso.

Más:

{11} Comentarios.

  1. Josep Sayol

    Yo realmente soy fan de este operador, simplifica mucho el código y lo hace bastante más legible.

    Como curiosidad para los que lo utilicen, hay que tener en cuenta que en PHP el operador ternario tiene asociatividad por la izquierda, al contrario que en JavaScript o en C. Es decir, si cogemos ese mismo ejemplo y lo pasamos a PHP:

    $a = 11;
    $numberLiteral = $a == 5 ? 'Five' :
                        $a == 7 ? 'Seven' :
                        $a == 11 ? 'Eleven' :
                        $a == 15 ? 'Fifteen' :
                        'Other Number';
     
    echo $numberLiteral; // aquí el ejemplo del artículo pone "a" pero deberia poner "numberLiteral" ;)
    

    El resultado que obtendremos no es «Eleven» como esperamos, sino «Fifteen». ¿Por qué? Pues porque el código que se está ejecutando en realidad es este:

    $numberLiteral = (((($a == 5 ? 'Five' :
                     $a == 7) ? 'Seven' :
                     $a == 11) ? 'Eleven' :
                     $a == 15) ? 'Fifteen' :
                     'Other Number');
    

    Si quisiéramos obtener el mismo resultado que espreamos en JavaScript, habría que reescribir el código de la siguiente manera:

    $a = 11;
    $numberLiteral = $a == 5 ? 'Five' :
                     ($a == 7 ? 'Seven' :
                     ($a == 11 ? 'Eleven' :
                     ($a == 15 ? 'Fifteen' :
                     'Other Number')));
     
    echo $numberLiteral;
    

    Un saludo 🙂

    • Carlos Benítez

      Gran aporte Josep!
      Es interesante comprobar como cada lenguaje implementa sus funcionalidades de manera distinta. Lástima que en PHP, con tanto paréntesis, se pierda parte de la legibilidad de esta estructura en Javascript.

      PD: Corregido el literal en el ejemplo 🙂
      Un saludo!

  2. JuniHH

    Cuando necesitaba hacer múltiples comparaciones, recurría precisamente a «switch», aunque uso con mucha frecuencia el operador ternario. Qué bueno saber que existe otra alternativa igual de simple basado en ese operador.

  3. Pasku

    Una de las operaciones más comunes cuando se trabaja con datos de entrada es el uso del operador «ifsetor», es usado para proporcionar un valor por defecto cuando una entrada no existe o no es valida.

    Lo habitual en estos casos es ver algo como esto:

    var safe = input ? input : 'default';

    Aplicando la sintaxis ifsetor, podemos simplificar la condición ternaria:

    var safe = input ?: 'default';
    • Carlos Benítez

      El ifsetor es un comando que funciona bien en PHP pero que no está implementado en el estándar Javascript.
      En este lenguaje, lo arreglaríamos con la asignación por igualdad booleana:

      var safe = input || 'default';
      

      El resultado es similar, solo que hay que tener en cuenta que se estarían evaluando también los falsy values.

      Gracias Pasku!

  4. Mekkon

    Yo confesaré que siempre que puedo, utilizo un array de índices para este tipo de cosas:

    var numbers = {
    '5' : 'Five',
    '7' ? 'Seven',
    '11' ? 'Eleven',
    '15' ? 'Fifteen' 
    };
    
    $numberLiteral = numbers[$a] || 'Other Number';
    

    no creo que el caso expuesto funcione, ya que el índice es un String y la variable contiene un número, pero va bien para hacerse una idea

    😉

    • Carlos Benítez

      Es una solución que yo también utilizo a menudo.

      La única pega es que es algo más lenta que la propuesta con el operador ternario. No es muy significativa pero cuando se trata de medir hasta el último milisegundo, hay que tenerlo en cuenta.

      Gracias por el aporte Mekkon!

  5. mekkon

    Pues sí, es más lenta, realmente se tienen que probar estas cosas, si no nunca se sabe

    como curiosidad, en ubuntu con firefox 3.6.13 apenas hay diferencias en cuanto a velocidad entre los tres tests, el ternario sigue siendo el más rápido de todas formas 😉

  6. NachoSoto

    Hay algo que no sé si es un typo o es que no lo he entendido: ¿dices que estas dos expresiones son equivalentes?

    var language = ‘Javascript’;
    var dynamic = ( language === «Javascript» ) ? true : false;
     
    console.log( dynamic ); // true

    y:

    var language = ‘Javascript’;
    var dynamic = language == ‘Javascript’;
     
    console.log( dynamic ); // true

    ¿Por qué una con == y la otra con ===?

    • Carlos Benítez

      Si: efectivamente es un typo. Para guardar la integridad, debería usarse siempre el comparador estricto «===».

      Gracias por el aviso!

  7. jorge

    El switch más rápido en chrome?
    Vaya, que le pasara a php con esa estructura

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *