javascript - multiple - Declaración de cambio para mayor que/menor que
switch javascript ejemplos (10)
Odio usar 30 declaraciones if
Tuve la misma situación últimamente, así es como lo resolví:
antes de:
if(wind_speed >= 18) {
scale = 5;
} else if(wind_speed >= 12) {
scale = 4;
} else if(wind_speed >= 9) {
scale = 3;
} else if(wind_speed >= 6) {
scale = 2;
} else if(wind_speed >= 4) {
scale = 1;
}
después:
var scales = [[4, 1], [6, 2], [9, 3], [12, 4], [18, 5]];
scales.forEach(function(el){if(wind_speed > el[0]) scale = el[1]});
Y si configura "1, 2, 3, 4, 5", puede ser incluso más simple:
var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
así que quiero usar una declaración de cambio como esta:
switch (scrollLeft) {
case (<1000):
//do stuff
break;
case (>1000 && <2000):
//do stuff
break;
}
Ahora sé que cualquiera de esas declaraciones ( <1000
) o ( >1000 && <2000
) no funcionará (por diferentes razones, obviamente). Lo que estoy preguntando es la forma más eficiente de hacerlo. Odio usar 30 declaraciones if
, por lo que prefiero usar la sintaxis del interruptor. ¿Hay algo que pueda hacer?
¿Qué estás haciendo exactamente en //do stuff
?
Es posible que pueda hacer algo como:
(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc.
Actualizando la respuesta aceptada (aún no puedo comentar). A partir del 1/12/16 usando la demo jsfiddle en cromo, switch-immediate es la solución más rápida.
Resultados: resolución de tiempo: 1.33
25ms "if-immediate" 150878146
29ms "if-indirect" 150878146
24ms "switch-immediate" 150878146
128ms "switch-range" 150878146
45ms "switch-range2" 150878146
47ms "switch-indirect-array" 150878146
43ms "array-linear-switch" 150878146
72ms "array-binary-switch" 150878146
Terminado
1.04 ( 25ms) if-immediate
1.21 ( 29ms) if-indirect
1.00 ( 24ms) switch-immediate
5.33 ( 128ms) switch-range
1.88 ( 45ms) switch-range2
1.96 ( 47ms) switch-indirect-array
1.79 ( 43ms) array-linear-switch
3.00 ( 72ms) array-binary-switch
Cuando miré las soluciones en las otras respuestas, vi algunas cosas que sé que son malas para el rendimiento. Iba a ponerlos en un comentario, pero pensé que era mejor compararlo y compartir los resultados. Puedes probarlo tú mismo . Debajo están mis resultados (ymmv) normalizados después de la operación más rápida en cada navegador (multiplique el tiempo 1.0 con el valor normalizado para obtener el tiempo absoluto en ms).
Chrome Firefox Opera MSIE Safari Node ------------------------------------------------------------------- 1.0 time 37ms 73ms 68ms 184ms 73ms 21ms if-immediate 1.0 1.0 1.0 2.6 1.0 1.0 if-indirect 1.2 1.8 3.3 3.8 2.6 1.0 switch-immediate 2.0 1.1 2.0 1.0 2.8 1.3 switch-range 38.1 10.6 2.6 7.3 20.9 10.4 switch-range2 31.9 8.3 2.0 4.5 9.5 6.9 switch-indirect-array 35.2 9.6 4.2 5.5 10.7 8.6 array-linear-switch 3.6 4.1 4.5 10.0 4.7 2.7 array-binary-switch 7.8 6.7 9.5 16.0 15.0 4.9
Prueba donde se realizó en Windows 7 32 bits con las siguientes versiones: Chrome 21.0.1180.89m , Firefox 15.0 , Opera 12.02 , MSIE 9.0.8112 , Safari 5.1.7 . El nodo se ejecutó en un cuadro Linux de 64 bits porque la resolución del temporizador en Node.js para Windows fue de 10 ms en lugar de 1 ms.
si-inmediato
Este es el más rápido en todos los entornos probados, excepto en ... ¡ drumroll MSIE! (sorpresa sorpresa). Esta es la forma recomendada de implementarlo.
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else
if-indirecto
Esta es una variante de switch-indirect-array
pero con if
states en su lugar y funciona mucho más rápido que switch-indirect-array
en casi todos los entornos probados.
values=[
1000, 2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else
interruptor-inmediato
Esto es bastante rápido en todos los entornos probados, y en realidad es el más rápido en MSIE. Funciona cuando puede hacer un cálculo para obtener un índice.
switch (Math.floor(val/1000)) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
rango de interruptores
Esto es aproximadamente de 6 a 40 veces más lento que el más rápido en todos los entornos probados, excepto en el caso de Opera, donde demora aproximadamente una vez y media. Es lento porque el motor tiene que comparar el valor dos veces para cada caso. Sorprendentemente, Chrome tarda casi 40 veces más en completar esto en comparación con la operación más rápida en Chrome, mientras que MSIE solo tarda 6 veces más. Pero la diferencia de tiempo real fue de solo 74ms a favor de MSIE a 1337ms (!).
switch (true) {
case (0 <= val && val < 1000): /* do something */ break;
case (1000 <= val && val < 2000): /* do something */ break;
...
case (29000 <= val && val < 30000): /* do something */ break;
}
switch-range2
Esta es una variante del switch-range
de switch-range
pero con solo una comparación por caso y, por lo tanto, más rápida, pero aún muy lenta, excepto en Opera. El orden de la declaración de caso es importante ya que el motor probará cada caso en el orden del código fuente ECMAScript262: 5 12.11
switch (true) {
case (val < 1000): /* do something */ break;
case (val < 2000): /* do something */ break;
...
case (val < 30000): /* do something */ break;
}
switch-indirect-array
En esta variante, los rangos se almacenan en una matriz. Esto es lento en todos los entornos probados y muy lento en Chrome.
values=[1000, 2000 ... 29000, 30000];
switch(true) {
case (val < values[0]): /* do something */ break;
case (val < values[1]): /* do something */ break;
...
case (val < values[29]): /* do something */ break;
}
array-linear-search
Esta es una combinación de una búsqueda lineal de valores en una matriz y la instrucción switch con valores fijos. La razón por la que uno querría usar esto es cuando los valores no se conocen hasta el tiempo de ejecución. Es lento en todos los entornos probados, y lleva casi 10 veces más tiempo en MSIE.
values=[1000, 2000 ... 29000, 30000];
for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
if (val < values[sidx]) break;
}
switch (sidx) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
array-binary-switch
Esta es una variante de array-linear-switch
pero con una búsqueda binaria. Desafortunadamente es más lento que la búsqueda lineal. No sé si es mi implementación o si la búsqueda lineal está más optimizada. También podría ser que el espacio de claves sea pequeño.
values=[0, 1000, 2000 ... 29000, 30000];
while(range) {
range = Math.floor( (smax - smin) / 2 );
sidx = smin + range;
if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}
switch (sidx) {
case 0: /* do something */ break;
...
case 29: /* do something */ break;
}
Conclusión
Si el rendimiento es importante, use if
-statements o switch
con valores inmediatos.
En mi caso (código de colores, un porcentaje, nada crítico para el rendimiento), rápidamente escribí esto:
function findColor(progress) {
const thresholds = [30, 60];
const colors = ["#90B451", "#F9A92F", "#90B451"];
return colors.find((col, index) => {
return index >= thresholds.length || progress < thresholds[index];
});
}
Esta es otra opción:
switch (true) {
case (value > 100):
//do stuff
break;
case (value <= 100)&&(value > 75):
//do stuff
break;
case (value < 50):
//do stuff
break;
}
No comprobado y no está seguro de si esto funcionará, pero ¿por qué no hacer algunas if statements
antes? Para establecer variables para la switch statement
.
var small, big;
if(scrollLeft < 1000){
//add some token to the page
//call it small
}
switch (//reference token/) {
case (small):
//do stuff
break;
case (big):
//do stuff;
break;
}
Puede crear un objeto personalizado con los criterios y la función correspondiente a los criterios
var rules = [{ lowerLimit: 0, upperLimit: 1000, action: function1 },
{ lowerLimit: 1000, upperLimit: 2000, action: function2 },
{ lowerLimit: 2000, upperLimit: 3000, action: function3 }];
Defina funciones para lo que quiere hacer en estos casos (defina function1, function2, etc.)
Y "evaluar" las reglas
function applyRules(scrollLeft)
{
for(var i=0; i>rules.length; i++)
{
var oneRule = rules[i];
if(scrollLeft > oneRule.lowerLimit && scrollLeft < oneRule.upperLimit)
{
oneRule.action();
}
}
}
Nota
Odio usar 30 declaraciones if
Muchas veces si las declaraciones son más fáciles de leer y mantener. Recomendaría lo anterior solo cuando tenga muchas condiciones y una posibilidad de mucho crecimiento en el futuro.
Actualizar
Como @Brad señaló en los comentarios, si las condiciones son mutuamente excluyentes (solo una de ellas puede ser verdadera a la vez), verificar el límite superior debería ser suficiente:
if(scrollLeft < oneRule.upperLimit)
siempre que las condiciones se definan en orden ascendente (primero la más baja, de 0 to 1000
y luego de 1000 to 2000
por ejemplo)
Una alternativa:
var scrollleft = 1000;
switch (true)
{
case (scrollleft > 1000):
alert(''gt'');
break;
case (scrollleft <= 1000):
alert(''lt'');
break;
}
Demostración: http://jsfiddle.net/UWYzr/
switch (scrollLeft/1000) {
case 0: // (<1000)
//do stuff
break;
case 1: // (>=1000 && <2000)
//do stuff;
break;
}
Solo funciona si tienes pasos regulares ...
EDIT: dado que esta solución sigue recibiendo upvotes, debo avisar que la solución de mofolo es mucho mejor.