JavaScript ha una valutazione "cortocircuito"?


101

Vorrei sapere se JavaScript ha una valutazione "cortocircuito" come && Operator in C #. In caso contrario, vorrei sapere se esiste una soluzione alternativa che abbia senso adottare.


2
Prego. Ho aggiunto https://www.google.com/search?q=site:stackoverflow.com+%scome scorciatoia di ricerca (Chrome / Firefox) per velocizzare le ricerche.
Rob W,


Risposte:


118

Sì, JavaScript ha una valutazione "cortocircuito".

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

Dimostrazione dal vivo

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

Dimostrazione dal vivo


8
Quindi il cortocircuito è lo standard in JS?
GibboK

1
Grazie gdoron, per favore aiutami a capire ... in C # ho anche un operatore binario come e quindi entrambi gli operandi devono essere veri per passare, invece con && in C
GibboK

1
@GibboK. Quindi, ovviamente, non può esserci a Short-circuitcon quell'operatore logico. Provalo tu stesso. Usa la mia demo.
gdoron supporta Monica il

2
@ GibboK: controlla questo riferimento dell'operatore . E sì, c'è anche un operatore binario AND in JS.
Bergi

5
@GibboK. SÌ nello standard! Ma buon commento, come ai tempi della magia della compilazione JIT nelle implementazioni javascript, si vuole davvero sapere se qualcosa è "standard" o potenzialmente soggetto all'implementazione. Il modo in cui una dichiarazione condizioni con operatori logici binari viene valutata e (a breve curcuit) è un comportamento standard ecma-international.org/ecma-262/5.1/#sec-11.11
humanityANDpeace

23

Questa risposta entra in grande dettaglio su come funziona in JavaScript, con tutti i trucchi e anche temi rilevanti come la precedenza degli operatori, se stai cercando una definizione rapida e capisci già come funziona il cortocircuito, ti consiglio di controllare altre risposte.


Quello che (pensavamo di) sapevamo finora:

Per prima cosa esaminiamo il comportamento che tutti conosciamo, all'interno del if()blocco, dove usiamo &&per verificare se le due cose sono true:

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

Ora, il tuo primo istinto è probabilmente quello di dire: "Ah sì, abbastanza semplice, il codice esegue l'istruzione se entrambi expr1e expr2vengono valutati come true"

Ebbene sì e no. Sei tecnicamente corretto, questo è il comportamento che hai descritto, ma non è esattamente così che viene valutato il codice e avremo bisogno di approfondire per comprenderlo appieno.


Come viene interpretato esattamente &&e ||?:

È ora di guardare "sotto il cofano di engine ". Consideriamo questo esempio pratico:

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);

Ebbene il risultato è 260.. ma perché? Per ottenere la risposta, dobbiamo capire come funziona la valutazione del cortocircuito.

Dalla definizione MDN l' &&operatore in expr1 && expr2viene eseguito come segue:

Se expr1può essere convertito in true, restituisce expr2; altrimenti, ritorna expr1.

Quindi questo significa, nel nostro esempio pratico, che const resviene valutato nel modo seguente:

  1. Invocando expr1-sanitise(0xFF)
  2. 0xFF è un numero esadecimale valido per 250, altrimenti tornerei NaN
  3. Il expr1restituito un valore "truthy", il tempo di esecuzione expr2 (altrimenti mi sarei fermata come NaNè falsy)
  4. Dal momento che userinputè truthy (un numero), posso aggiungere +5ad esso
  • "Verità" significa che l'espressione può essere valutata come vera. Ecco un elenco di espressioni veritiere e false .

Quindi qui, siamo stati in grado di evitare ifblocchi aggiuntivi e ulteriori isNaNcontrolli con un semplice utilizzo &&dell'operatore.


Come funziona davvero:

A questo punto, dovremmo almeno avere un'immagine di come il file gli operatori lavorano. La regola universale va:

  • (some falsy expression) && expr valuterà un'espressione falsa
  • (some truthy expression) || expr valuterà in modo veritiero

Ecco alcuni ulteriori esempi per una migliore comprensione:

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');`
*/


Un'ultima cosa fastidiosa, ma molto importante [precedenza degli operatori]:

Bene, spero che tu stia imparando! L'ultima cosa che dobbiamo sapere è una regola sulla precedenza degli operatori, ovvero:

  • L' &&operatore viene sempre eseguito prima ||dell'operatore.

Considera il seguente esempio:

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

Questo tornerà come, forse in modo confuso per alcuni come a(). La ragione è abbastanza semplice, è solo la nostra vista che ci inganna, perché siamo abituati a leggere da sinistra a destra. Prendiamo il console.log()e cosa no e concentriamoci esclusivamente sulla valutazione

true || false && false

Ora per avvolgere la testa intorno a questo:

  1. Abbiamo detto che l' &&operatore ha la precedenza, quindi viene valutato per primo. Per aiutarci a immaginare meglio la valutazione, pensa alla definizione

    expr1 && expr2

    Dove:

    • expr2 è false
    • expr1 è true || false
  2. Quindi questa era la parte difficile, ora true || falseviene valutata (il expr1- lato sinistro del &&).

    • Dato che l' ||operatore interrompe l'esecuzione se expr1 || expr2in viene expr1valutato come true, expr1viene eseguito e l'esecuzione del codice si interrompe.
  3. Il valore restituito è true

Beh ... era piuttosto complicato, tutto a causa di poche regole e semantiche strane. Ma ricorda, puoi sempre sfuggire alla precedenza dell'operatore con ()- proprio come in matematica

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()  
*/


Vorrei 1) non usare la parola "compilatore". "engine" è più preciso. 2) Non parlare expr1e expr2 o condition1o qualsiasi altra cosa, che è solo confusione. Decidi per uno, potresti anche introdurre variabili locali, ad es. const expr1 = true; if(expr1 && ...)
Jonas Wilms

@JonasWilms, grazie per l'input, ha modificato la risposta di conseguenza.
Samuel Hulla

1
Questo ancora non risponde direttamente alla domanda posta.
Kevin B

7
Questa è la migliore "grande risposta che non risponde esplicitamente alla domanda" che io abbia mai visto ...
Gerardo Furtado

1
Questa è la risposta giusta con una spiegazione profonda, dovrebbe essere contrassegnata come accettata e votata molto più di quanto non sia attualmente!
Alexander Kim
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.