Uma declaração javascript if com várias condições testa todas elas?

100

Em javascript, ao usar uma instrução if com várias condições para testar, o javascript testa todas elas independentemente, ou vai parar antes de testar todas se já for falso?

Por exemplo:

 a = 1
 b = 2
 c = 1

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

O javascript testará todas as 3 dessas condições ou, depois de ver que b não é igual a 1 e, portanto, é falso, sairá da instrução?

Eu pergunto do ponto de vista do desempenho. Se, por exemplo, estou testando 3 seletores jQuery complexos, prefiro que o jQuery não atravesse o DOM 3 vezes se for óbvio pelo primeiro que ele retornará FALSO. (Nesse caso, faria mais sentido aninhar 3 instruções if).

ADENDO: Mais curiosidade, qual o termo adequado para isso? Percebi que muitos de vocês usam o termo 'curto-circuito'. Além disso, alguns idiomas fazem isso e outros não?

DA.
fonte
@Josh: Eu aprecio completamente a ideia de que isso é micro-otimização. O que é bom saber. Dito isso, se uma opção for mais otimizada do que outra, suponho que seja bom saber e adquirir o hábito de usar esse método. (Além disso, eu também estava muito curioso para saber a resposta)
DA.
21
A rigor, essa não é uma otimização prematura. Em linguagens com lógica de curto-circuito, é importante saber sob quais condições alguns métodos não serão executados; se você está contando com seus efeitos colaterais, por exemplo.
Rob
5
Aqui está outra pergunta sobre "avaliação de curto-circuito": stackoverflow.com/questions/1232603/…
David
@David. Obrigado! Leitura interessante.
DA.

Respostas:

151

O &&operador "causa um curto-circuito" - isto é, se a condição da esquerda for falsa, ele não se preocupa em avaliar a condição da direita.

Da mesma forma, o ||operador entra em curto-circuito se a condição à esquerda for verdadeira.

EDIT: Porém, você não deve se preocupar com o desempenho até que tenha feito o benchmarking e determinado que é um problema. A micro-otimização prematura é a ruína da manutenção.

Anon.
fonte
1
Excelente resposta (tanto a parte técnica como a questão de gestão). obrigado!
DA.
5
Se você quiser que ele execute todas as partes da instrução booleana, você pode usar & e | para e / ou repspectivamente
Zoidberg
25
Essa condição não é necessariamente sempre sobre desempenho. Às vezes, você pode estar fazendo uma verificação nula e dizer se sua verificação nula é a condição a e, em seguida, tentar fazer a (b == valor + 1) para sua segunda verificação, obterá um erro se todas as três condições forem verificadas.
infocyde
4
Na verdade, curto-circuito não tem a ver com desempenho. A pergunta original, entretanto, era do ponto de vista do desempenho.
Anon.
1
muito bom. Fazer esse tipo de microotimização (entre outros) pode ter um grande impacto dentro de um loop de eventos de rolagem, digamos, para o cálculo de paralaxe de vários elementos, por exemplo, ou mesmo uma barra aderente. Veja este exemplo: if (!barSticky && bar.parent().offset().top <= document.documentElement.scrollTop)a segunda condição é um cálculo mais caro, a primeira é apenas um booleano. :)
antoni
13

Do ponto de vista do desempenho, isso não é uma micro-otimização.

Se tivermos 3 variáveis ​​booleanas, a, b, c, isso é uma micro-otimização.

Se chamarmos 3 funções que retornam variáveis ​​booleanas, cada função pode levar muito tempo, e não só é importante saber quais são os curtos-circuitos, mas em que ordem. Por exemplo:

if (takesSeconds() && takesMinutes())

é muito melhor que

if (takesMinutes() && takesSeconds())

se ambos têm a mesma probabilidade de retornar false.

Brad
fonte
12

É por isso que você pode fazer em código javascript como

var x = x || 2;

O que significa que se x for indefinido ou 'falso', o valor padrão é 2.

azazul
fonte
3
Isso poderia funcionar mesmo se JS não suportasse avaliação de curto-circuito.
pswg de
1
Isso é equivalente a um ternário?
Mark Carpenter Jr
10

No caso de alguém está se perguntando se existe uma maneira de forçar a avaliação de todas as condições, em alguns casos, os operadores bit a bit &e |pode ser usado

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

Eles devem ser usados ​​com muito cuidado porque os operadores bit a bit são operadores aritméticos que funcionam em bits únicos de seu operando e nem sempre podem funcionar como uma versão "sem curto-circuito" de &&e||

Exemplo:

-2147483648 && 1 = 1 

mas

-2147483648 & 1 = 0

Espero que ajude quem chegou aqui em busca de informações como esta (como eu) e obrigado ao @Max pela correção e contra-exemplo

Ivcandela
fonte
1
Esta resposta está errada. & e | são operadores bit a bit, eles NÃO são 'versões sem curto-circuito de && e ||'. Operadores bit a bit são operadores aritméticos que funcionam em bits únicos de seu operando. Exemplo: -2147483648 && 1 = 1 mas -2147483648 & 1 = 0. Mais informações aqui: en.wikipedia.org/wiki/Bitwise_operation
Máx.
1
@Max, na verdade, eu não sabia disso, tenho usado isso (o que agora chamo de "truque") desde que estava estudando C. Felizmente, essas entradas que quebrariam meu código nunca apareceram.
Corrigi
@DJDaveMark desculpe, não consegui fazer sua false && (alert(""))solução funcionar: /
ivcandela
@ivcandela Nem eu. Se eu não estivesse no meu telefone, eu o teria testado primeiro; o) Pena que você não pode editar comentários. Acabei de excluí-lo e adicionar outro abaixo
DJDaveMark
A maneira mais simples e melhor de forçar a avaliação é salvar os resultados em variáveis ​​e, em seguida, testar as variáveis, ou seja:var a=false; var b=check(); alert(a && b);
DJDaveMark
7

Ele só testará todas as condições se as primeiras forem verdadeiras, teste você mesmo:

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

Ele causa um curto-circuito - apenas aeb serão comparados em seu exemplo.

David M
fonte
3

Outro motivo para interromper a avaliação com 1 ou mais parâmetros à esquerda.

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

a segunda avaliação depende de a primeira ser verdadeira e não gerará um erro de compilação se response.authResponse for nulo ou indefinido etc porque a primeira condição falhou.

Outras linguagens tiveram esse problema no início e acho que é uma abordagem padrão na construção de compiladores agora.

PazoozaTest Pazman
fonte
2

Ele sai depois de ver que b não é igual a um.

Annie
fonte
2

Para qualquer um sobre esta questão confuso porque não está vendo o comportamento de curto-circuito ao usar um ||em conjunto com um ?operador como este:

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

parece que a regra de curto-circuito não está funcionando. Por que está avaliando o segundo termo do ||(verdadeiro? 2: 3) quando o primeiro é verdadeiro? Acontece que é um problema de ordem de operações porque o acima é equivalente a

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

com o ||primeiro avaliado e o ?segundo avaliado. O que você provavelmente quer é:

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

BrightEyed
fonte