JavaScript a-t-il une évaluation «court-circuit»?

101

Je voudrais savoir si JavaScript a une évaluation "court-circuit" comme && Operator en C #. Sinon, j'aimerais savoir s'il existe une solution de contournement qui a du sens à adopter.

GibboK
la source
2
De rien. J'ai ajouté https://www.google.com/search?q=site:stackoverflow.com+%sun raccourci de recherche (Chrome / Firefox) pour accélérer les recherches.
Rob W
Ici aussi une réponse à ma question developer.mozilla.org/en-US/docs/Web/JavaScript/Reference
...
Autres ressources utiles: Le || question d'évaluation La
Samuel Hulla

Réponses:

118

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

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

DÉMO en direct

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

DÉMO en direct

gdoron soutient Monica
la source
8
Alors court-circuit c'est la norme dans JS?
GibboK
1
Merci gdoron, aidez-moi à comprendre ... en C # j'ai aussi un opérateur binaire comme & donc à la fois l'opérande doit être vrai pour passer, à la place avec && en C
GibboK
1
@GibboK. Alors, évidemment, il ne peut pas y avoir de Short-circuitavec cet opérateur logique. Essayez-le vous-même. Utilisez ma démo.
gdoron soutient Monica le
2
@GibboK: consultez cette référence d'opérateur . Et oui, il existe également un opérateur binaire AND dans JS.
Bergi
5
@GibboK. OUI dans la norme! Mais bon commentaire, comme à l'époque de JIT-compiling-magic dans les implémentations javascript, on veut vraiment savoir si quelque chose est "standard", ou potentiellement sujet à l'implémentation. La façon dont une instruction de condition avec les opérateurs logiques binaires est évalué et (court curcuit) est un comportement standard ecma-international.org/ecma-262/5.1/#sec-11.11
humanityANDpeace
23

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


Ce que nous (pensions que nous) savions jusqu'à présent:

Commençons par inspecter le comportement que nous connaissons tous, à l'intérieur du if()bloc, 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, assez simple, le code exécute l'instruction si les deux expr1et expr2sont évalués comme true'

Eh bien, oui et non. Vous avez techniquement raison, c'est le comportement que vous avez décrit, mais ce n'est pas exactement ainsi que le code est évalué et nous devrons approfondir afin de bien comprendre.


Comment est interprété exactement le &&et ||?:

Il est temps de regarder "sous le capot du engine ". Prenons 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 des courts-circuits.

Par la définition MDN, l' &&opérateur dans expr1 && expr2est exécuté comme suit:

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

Cela signifie donc, dans notre exemple pratique, que le const resest é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 a expr1renvoyé une valeur "véridique", temps d'exécution expr2 (sinon je m'arrêterais comme NaNfaux)
  4. Depuis userinputest truthy (un numéro), je peux ajouter +5à ce
  • «Truthy» signifie que l'expression peut être évaluée comme vraie. Voici une liste d' expressions véridiques et fausses .

Donc ici, nous avons pu éviter des ifblocages supplémentaires et des isNaNcontrôles supplémentaires avec une simple utilisation de l' &&opérateur.


Comment ça marche vraiment:

À présent, nous devrions au moins avoir une image de la façon dont le les opérateurs travaillent. La règle universelle va:

  • (some falsy expression) && expr évaluera une expression erroné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 [Operator Precedence]:

Bien, j'espère que vous comprenez le coup! La dernière chose que nous devons savoir 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 reviendra comme, peut-être déroutant pour certains a(). La raison est assez simple, c'est juste notre vue qui nous trompe, parce que nous avons l'habitude de 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, pour comprendre ceci:

  1. Nous avons dit que l' &&opérateur a la priorité, donc il est évalué comme 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 délicate, maintenant true || falseest évaluée (le expr1- côté gauche de la &&).

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

Eh bien… c'était assez délicat, tout cela à cause de quelques règles et sémantiques étranges. Mais rappelez-vous que vous pouvez toujours échapper à la priorité des opérateurs avec ()- comme en maths

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
la source
Je n'utiliserais pas 1) le mot «compilateur». "moteur" est plus précis. 2) Ne pas parler de expr1et expr2 ou condition1ou de quoi que ce soit, c'est juste déroutant. Choisissez-en un, vous pouvez également introduire des variables locales, par exemple. const expr1 = true; if(expr1 && ...)
Jonas Wilms
@JonasWilms merci pour la contribution, a modifié la réponse en conséquence.
Samuel Hulla
1
Cela ne répond toujours pas directement à la question posée.
Kevin B
7
C'est la meilleure "bonne réponse qui ne répond pas explicitement à la question" que j'ai jamais vue ...
Gerardo Furtado
1
C'est la bonne réponse avec une explication approfondie, devrait être marquée comme acceptée et votée beaucoup plus qu'elle ne l'est actuellement!
Alexander Kim