O JavaScript tem avaliação de “curto-circuito”?

101

Gostaria de saber se JavaScript tem avaliação de "curto-circuito" como && Operator em C #. Caso contrário, gostaria de saber se há uma solução alternativa que faça sentido adotar.

GibboK
fonte
2
De nada. Eu adicionei https://www.google.com/search?q=site:stackoverflow.com+%scomo um atalho de pesquisa (Chrome / Firefox) para acelerar as pesquisas.
Rob W
Também aqui está uma resposta à minha pergunta developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GibboK
Outros recursos úteis: O || pergunta de avaliação A
Samuel Hulla

Respostas:

118

Sim, o JavaScript tem avaliação de "curto-circuito".

if (true == true || foo.foo){
    // Passes, no errors because foo isn't defined.
}

Demonstração ao vivo

if (false && foo.foo){
    // Passes, no errors because foo isn't defined.
}

Demonstração ao vivo

gdoron está apoiando Monica
fonte
8
Então, curto-circuito é o padrão em JS?
GibboK
1
Obrigado gdoron, por favor me ajude a entender ... em C # eu também tenho um operador binário como & então ambos os operandos devem ser verdadeiros para passar, em vez de && em C
GibboK
1
@GibboK. Então, obviamente, não pode haver um Short-circuitcom esse operador lógico. Apenas tente você mesmo. Use minha demonstração.
gdoron está torcendo para Monica em
2
@GibboK: Verifique esta referência de operador . E sim, há um operador binário AND em JS também.
Bergi,
5
@GibboK. SIM no padrão! Mas um bom comentário, como em tempos de JIT-compiling-magic em implementações de javascript, alguém realmente quer saber se algo é "o padrão", ou potencialmente sujeito à implementação. A forma como uma instrução de condição com binários Operadores lógicos é avaliada e (short-curcuit) é um comportamento padrão ecma-international.org/ecma-262/5.1/#sec-11.11
humanityANDpeace
23

Essa resposta fornece muitos detalhes sobre como funciona em JavaScript, com todas as pegadinhas e também temas relevantes como precedência de operador, se você está procurando uma definição rápida e já entende como funciona o curto-circuito, recomendo verificar outras respostas.


O que nós (pensávamos) sabíamos até agora:

Primeiro, vamos inspecionar o comportamento com o qual todos estamos familiarizados, dentro do if()bloco, onde usamos &&para verificar se as duas coisas são true:

if (true && true) {
   console.log('bar');
} 

Agora, seu primeiro instinto é provavelmente dizer: 'Ah sim, muito simples, o código executa a instrução se ambos expr1e expr2forem avaliados como true'

Bem, sim e não. Você está tecnicamente correto, esse é o comportamento que você descreveu, mas não é exatamente assim que o código é avaliado e precisaremos nos aprofundar para entendê-lo completamente.


Como exatamente é o &&e ||interpretado ?:

É hora de olhar "sob o capô do motor ". Vamos considerar este exemplo prático:

function sanitise(x) {
  if (isNaN(x)) {
    return NaN;
  }
  return x;
}

let userinput = 0xFF; // as an example
const res = sanitise(userinput) && userinput + 5

console.log(res);

Bem, o resultado é 260.. mas por quê? Para obter a resposta, precisamos entender como funciona a avaliação de curto-circuito.

Pela Definição MDN, o &&operador em expr1 && expr2é executado da seguinte forma:

Se expr1pode ser convertido para true, retorna expr2; mais, retorna expr1.

Isso significa que, em nosso exemplo prático, o const resé avaliado da seguinte maneira:

  1. Invocando expr1-sanitise(0xFF)
  2. 0xFF é um número hexadecimal válido para 250, caso contrário, eu retornaria NaN
  3. O expr1retornou um valor "verdadeiro", hora de execução expr2 (caso contrário, eu pararia porque NaNé falso)
  4. Visto que userinputé verdadeiro (um número), posso adicionar +5a ele
  • "Verdadeiro" significa que a expressão pode ser avaliada como verdadeira. Aqui está uma lista de truthy e Falsas expressões.

Então, aqui, fomos capazes de evitar ifbloqueios adicionais e isNaNverificações adicionais com um simples uso do &&operador.


Como realmente funciona:

Agora, devemos ter pelo menos uma imagem de como o os operadores trabalham. A regra universal é:

  • (some falsy expression) && expr será avaliado como expressão falsa
  • (some truthy expression) || expr avaliará a expressão verdadeira

Aqui estão mais alguns exemplos para melhor compreensão:

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() && b() ){
     console.log('foobar'); 
}

//Evaluates a() as false, stops execution.

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() || b() ){
     console.log('foobar'); 
}

/* 1. Evaluates a() as false
   2. So it should execute expr2, which is `b()`
   3. b() returned as true, executing statement `console.log('foobar');`
*/


Uma última coisa incômoda, mas muito importante [precedência do operador]:

Legal, espero que você esteja pegando o jeito! A última coisa que precisamos saber é uma regra sobre a precedência do operador, que é:

  • O &&operador é sempre executado antes do ||operador.

Considere o seguinte exemplo:

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log(a() || b() && c());

// returns a() and stops execution

Isso retornará como, talvez de forma confusa para alguns como a(). A razão é bastante simples, é apenas a nossa visão que meio que nos engana, porque estamos acostumados a ler da esquerda para a direita. Vamos tirar o console.log()e o que não é e focar puramente na avaliação

true || false && false

Agora, para entender isso:

  1. Dissemos que o &&operador tem precedência, portanto, ele é avaliado como o primeiro. Para nos ajudar a imaginar melhor a avaliação, pense na definição

    expr1 && expr2

    Onde:

    • expr2 é false
    • expr1 é true || false
  2. Então essa foi a parte complicada, agora true || falseé avaliada (o expr1- lado esquerdo do &&).

    • Dado que o ||operador interrompe a execução se expr1 || expr2in for expr1avaliado como verdadeiro, o expr1é executado e a execução do código é interrompida.
  3. O valor retornado é true

Bem ... isso foi bem complicado, tudo por causa de algumas regras e semânticas estranhas. Mas lembre-se, você sempre pode escapar da precedência do operador com o ()- assim como na matemática

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log((a() || b()) && c());

/* 1. The () escape && operator precedence
   2. a() is evaluated as false, so expr2 (c()) to be executed
   3. c()  
*/

Samuel Hulla
fonte
Eu 1) não usaria a palavra "compilador". "motor" é mais preciso. 2) Não falar sobre expr1e expr2 ou condition1ou qualquer outra coisa, que está apenas confuso. Decida por um, você também pode introduzir variáveis ​​locais, por exemplo. const expr1 = true; if(expr1 && ...)
Jonas Wilms
@JonasWilms obrigado pela contribuição e alterou a resposta de acordo.
Samuel Hulla
1
Isso ainda não responde diretamente à pergunta feita.
Kevin B
7
Esta é a melhor "ótima resposta que não responde explicitamente à pergunta" que eu já vi ...
Gerardo Furtado
1
Esta é a resposta certa com uma explicação profunda, deve ser marcada como aceita e votada muito mais do que é atualmente!
Alexander Kim