web-dev-qa-db-fra.com

JavaScript a-t-il une évaluation "Court-circuit"?

Je voudrais savoir si JavaScript a une évaluation de "court-circuit" comme && Operator in C #. Si non, j'aimerais savoir s'il existe une solution de contournement qu'il est logique d'adopter.

89
GibboK

Oui, JavaScript a une évaluation de "court-circuit".

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

Live DEMO

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

Live DEMO

104
gdoron

Cette réponse explique en détail comment court-circuitage fonctionne en JavaScript, avec tous les thèmes pertinents, tels que la priorité des opérateurs, si vous recherchez une définition rapide et déjà comprendre comment fonctionne le court-circuit, je recommanderais de vérifier les autres réponses.


Ce que nous savions savoir jusqu'à présent:

D'abord, examinons le comportement que nous connaissons tous, à l'intérieur du bloc if(), où nous utilisons && Pour vérifier si les deux choses sont true:

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

Maintenant, votre premier instinct est probablement de dire: 'Ah oui, c'est très simple, le code exécute l'instruction si expr1 Et expr2 Sont évalués comme true '

Eh bien oui et non. Vous êtes techniquement correct, c’est le comportement que vous avez décrit, , mais ce n’est pas exactement la façon dont le code est évalué et nous devrons approfondir davantage afin de: entièrement compris.


Comment interprètent-on exactement && Et || ?:

Il est temps de regarder "sous le capot du moteur javascript ". Considérons cet exemple pratique:

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

Eh bien, le résultat est 260 .. mais pourquoi? Afin d'obtenir la réponse, nous devons comprendre comment fonctionne l'évaluation du court-circuit.

Par le définition MDN , l'opérateur && Dans expr1 && expr2 Est exécuté comme suit:

Si expr1 Peut être converti en true, retourne expr2; sinon, retourne expr1.

Cela signifie donc que, dans notre exemple pratique, le const res Est évalué de la manière suivante:

  1. Invoquer expr1 - sanitise(0xFF)
  2. 0xFF Est un nombre hexadécimal valide pour 250, sinon je retournerais NaN
  3. Le expr1 A renvoyé une valeur "vérité", le temps d’exécuter expr2 (sinon je m'arrêterais car NaN est faux)
  4. Puisque userinput est une vérité (un nombre), je peux y ajouter +5
  • "Vérité" signifie que l'expression peut être évaluée comme vraie. Voici une liste d'expressions vérité et fausseté .

Donc ici, nous avons pu éviter des blocs if supplémentaires et d'autres vérifications isNaN avec une utilisation simple de l'opérateur &&.


Comment ça marche vraiment:

A présent, nous devrions au moins avoir une idée du fonctionnement des opérateurs court-circuit . La règle universelle va:

  • (some falsy expression) && expr Évaluera l'expression falsifiée
  • (some truthy expression) || expr Évaluera l'expression de la vérité

Voici quelques exemples supplémentaires pour une meilleure compréhension:

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

Une dernière chose embêtante, mais très importante [Précédente d'opérateur]:

Sympa, j'espère que vous avez compris! La dernière chose à connaître est une règle sur la priorité des opérateurs, à savoir:

  • L'opérateur && Est toujours exécuté avant l'opérateur ||.

Prenons l'exemple suivant:

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

Cela retournera sous la forme peut-être déroutante pour certains comme a(). La raison est assez simple, c'est juste notre vision qui nous trompe, parce que nous sommes habitués à lire de gauche à droite. Prenons le console.log() et ce qui ne l'est pas et concentrons-nous uniquement sur l'évaluation

true || false && false

Maintenant, enroulez-vous la tête:

  1. Nous avons dit que l'opérateur && Avait la priorité et qu'il était donc évalué en premier. Pour nous aider à mieux imaginer l'évaluation, pensez à la définition

    expr1 && expr2
    

    Où:

    • expr2 Est false
    • expr1 Est true || false
  2. C'était donc la partie la plus délicate, maintenant true || false Est évalué (le expr1 - côté gauche du &&).

    • Étant donné que l'opérateur || Arrête l'exécution si expr1 || expr2 Dans expr1 Est évalué comme une vérité, le expr1 Est exécuté et l'exécution du code s'arrête.
  3. La valeur renvoyée est true

Eh bien… c'était assez compliqué, à cause de peu de règles et de sémantiques étranges. Mais rappelez-vous, vous pouvez toujours échapper à la priorité des opérateurs avec le () - comme en mathématiques

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