¿Una declaración if de JavaScript con múltiples condiciones las prueba todas?

100

En javascript, cuando se usa una declaración if con múltiples condiciones para probar, ¿javascript las prueba todas independientemente, o se resguardará antes de probarlas todas si ya es falsa?

Por ejemplo:

 a = 1
 b = 2
 c = 1

 if (a==1 && b==1 && c==1)

¿Javascript probará las 3 condiciones o, después de ver que b no es igual a 1 y, por lo tanto, es falso, saldrá de la declaración?

Pregunto desde el punto de vista del desempeño. Si, por ejemplo, estoy probando 3 selectores complejos de jQuery, preferiría que jQuery no atraviese el DOM 3 veces si es obvio a través del primero que devolverá FALSO. (En cuyo caso, tendría más sentido anidar 3 declaraciones if).

ADDENDUM: Más que una curiosidad, ¿cuál es el término adecuado para esto? Noto que muchos de ustedes usan el término "cortocircuito". Además, ¿algunos idiomas hacen esto y otros no?

DA.
fuente
@Josh: Aprecio completamente la idea de que esto sea una microoptimización. Es bueno saberlo. Dicho esto, si una opción está más optimizada que otra, asumo que es bueno saberlo y adquirir el hábito de usar dicho método. (Además, bueno, también tenía mucha curiosidad por la respuesta)
DA.
21
Estrictamente hablando, esta no es una optimización prematura. En lenguajes con lógica de cortocircuito, es importante saber bajo qué condiciones no se ejecutarán algunos métodos; si confía en sus efectos secundarios, por ejemplo.
Rob
5
Aquí hay otra pregunta sobre la "evaluación de cortocircuitos": stackoverflow.com/questions/1232603/…
David
@David. ¡Gracias! Interesante lectura.
DA.

Respuestas:

151

El &&operador "cortocircuita", es decir, si la condición de la izquierda es falsa, no se molesta en evaluar la correcta.

De manera similar, el ||operador cortocircuita si la condición izquierda es verdadera.

EDITAR: Sin embargo, no debe preocuparse por el rendimiento hasta que haya evaluado y determinado que es un problema. La microoptimización prematura es la pesadilla de la mantenibilidad.

Luego.
fuente
1
Excelente respuesta (tanto en la parte técnica como en la gestión). ¡Gracias!
DA.
5
Si alguna vez desea que ejecute todas las partes de la declaración booleana, puede usar & y | para y yo repspectivamente
Zoidberg
25
Esta condición no siempre tiene que ver con el rendimiento. A veces, puede estar haciendo una verificación nula y decir si su verificación nula es la condición ay luego intenta hacer un (b == valor + 1) para su segunda verificación, obtendrá un error si se verificaron las tres condiciones.
infocyde
4
De hecho, el cortocircuito no se trata de rendimiento. La pregunta original, sin embargo, era desde el punto de vista del desempeño.
Anon.
1
muy bien. Hacer este tipo de microoptimización (entre otras) puede tener un gran impacto dentro de un bucle de evento de desplazamiento, digamos para el cálculo de paralaje de múltiples elementos, por ejemplo, o incluso una barra adhesiva. tome este ejemplo: if (!barSticky && bar.parent().offset().top <= document.documentElement.scrollTop)la segunda condición es un cálculo más costoso, la primera es solo un booleano. :)
antoni
13

Desde el punto de vista del rendimiento, esto no es una microoptimización.

Si tenemos 3 variables booleanas, a, b, c, eso es una microoptimización.

Si llamamos a 3 funciones que devuelven variables booleanas, cada función puede llevar bastante tiempo, y no solo es importante conocer estos cortocircuitos, sino en qué orden. Por ejemplo:

if (takesSeconds() && takesMinutes())

es mucho mejor que

if (takesMinutes() && takesSeconds())

si es igualmente probable que ambos devuelvan falso.

Puntilla
fuente
12

Es por eso que puedes hacer en código javascript como

var x = x || 2;

Lo que significaría que si x no está definido o es 'falso', el valor predeterminado es 2.

azazul
fuente
3
Esto podría funcionar incluso si JS no admitiera la evaluación de cortocircuitos.
pswg
1
¿Es esto el equivalente a un ternario?
Mark Carpenter Jr
10

En caso de que alguien se pregunte si hay una manera de forzar la evaluación de todas las condiciones, en algunos casos se pueden usar los operadores bit a bit &y|

var testOr = true | alert(""); //alert pops up
var testAnd = false & alert(""); //alert pops up

Estos deben usarse con mucho cuidado porque los operadores bit a bit son operadores aritméticos que funcionan en bits individuales de su operando y no siempre pueden funcionar como una versión "sin cortocircuito" de &&y||

Ejemplo:

-2147483648 && 1 = 1 

pero

-2147483648 & 1 = 0

Espero que ayude a alguien que llegó aquí buscando información como esta (como yo) y gracias a @Max por la corrección y el contraejemplo

ivcandela
fuente
1
Esta respuesta es incorrecta. & y | son operadores bit a bit, NO son 'versiones sin cortocircuito de && y ||'. Los operadores bit a bit son operadores aritméticos que funcionan en bits individuales de su operando. Ejemplo: -2147483648 && 1 = 1 pero -2147483648 & 1 = 0. Más información aquí: en.wikipedia.org/wiki/Bitwise_operation
Max
1
@Max en realidad no sabía esto, he estado usando esto (lo que ahora llamo "truco") desde que estaba estudiando C. Afortunadamente, tales entradas que habrían roto mi código nunca aparecieron.
Corrigí
@DJDaveMark lo siento, no pude conseguir que tu false && (alert(""))solución funcionara: /
ivcandela
@ivcandela Yo tampoco. Si no estuviera en mi teléfono, lo habría probado primero; o) Lástima que no puedas editar los comentarios. Lo
eliminé
La forma más sencilla y mejor de forzar la evaluación es guardar los resultados en variables y luego probarlas con las variables, es decir:var a=false; var b=check(); alert(a && b);
DJDaveMark
7

Solo probará todas las condiciones si las primeras son verdaderas, pruébelo usted mismo:

javascript: alert (false && alert("A") && false);
albertein
fuente
3

Se produce un cortocircuito: solo se compararán a y b en su ejemplo.

David M
fuente
3

Otra razón por la cual detener la evaluación con 1 o más parámetros a la izquierda.

if (response.authResponse && (response.authResponse.accessToken! = user.accessToken)) {...}

la segunda evaluación se basa en que la primera es verdadera y no arrojará un error de compilación si response.authResponse es nulo o indefinido, etc. porque la primera condición falló.

Otros lenguajes tuvieron este problema en los primeros días y creo que ahora es un enfoque estándar en la creación de compiladores.

PazoozaTest Pazman
fuente
2

Sale después de ver que b no es igual a uno.

Annie
fuente
2

Para cualquiera en esta pregunta confundido porque no está viendo el comportamiento de cortocircuito cuando usa un ||junto con un ?operador así:

x = 1 || true ? 2 : 3 // value of x will be 2, rather than 1 as expected

parece que la regla de cortocircuito no funciona. ¿Por qué está evaluando el segundo término del ||(¿verdadero? 2: 3) cuando el primero es verdadero? Resulta ser un problema de orden de operaciones porque lo anterior es equivalente a

x = (1 || true) ? 2 : 3

con el ||evaluado primero y el ?evaluado segundo. Lo que probablemente quieras es:

x = 1 || (true ? 2 : 3)

BrightEyed
fuente