Conditions multiples dans la déclaration if des deux côtés de l'opérateur logique

J'éprouvais plusieurs arguments dans une déclaration if des deux côtés de l'opérateur logique. J'ai d'abord commencé avec le || L'opérateur, qui a fonctionné comme prévu:

var a = 'apple', b = 'banana', c = 'cherry'; if (a == 'banana' || a == 'apple' || b == 'banana' || b == 'apple') { console.log('example 1') // returns } if ((a || b) == 'banana' || (a || b) == 'apple') { console.log('example 2') // returns } if (a == ('apple' || 'banana') || b == ('apple' || 'banana')) { console.log('example 3') // returns } if ((a || b) == ('apple' || 'banana')) { console.log('example 4') // returns } 

Jusqu'à présent, aucun résultat inattendu. Cependant, lorsqu'on suit une structure similaire lors du remplacement de || Opérateur pour l'opérateur &&, les choses ne fonctionnent pas bien comme je l'espère.

 if ((a == 'banana' && b == 'apple') || (a == 'apple' && b == 'banana')) { console.log('example 5') // returns } if (((a || b) == 'banana') && ((a || b) == 'apple')) { console.log('example 6') // DOESN'T RETURN } if ((a || b) == 'banana') { console.log('example 6a') // DOESN'T RETURN - consistent with example 6 } if ((a == ('apple' || 'banana')) && (b == ('apple' || 'banana'))) { console.log('example 7') // DOESN'T RETURN } if (a == ('apple' || 'banana')) { console.log('example 7a') // returns - inconsistent with example 7 } if (b == ('apple' || 'banana')) { console.log('example 7b') // DOESN'T RETURN - inconsistent with example 7a } if ((a && b) == ('apple' || 'banana')) { console.log('example 8') // DOESN'T RETURN } if ('apple' == (a || b) && 'banana' == (a || b)) { console.log('example 9') // DOESN'T RETURN } 

Maintenant, je me demande: existe-t-il un défaut dans ma logique ou ne peut-il pas être fait de cette façon? Mon but est d'écrire ces déclarations si aussi courtes que possible, dans le but de la lisibilité et de la facilité d'entretien. De toute évidence, je suis en train d'explorer les possibilités.

Quelqu'un sait-il un moyen d'y parvenir? Surtout l'exemple 7 / 7a / 7b me paraît particulier, car il produit des résultats incohérents malgré une structure similaire [Fiddle]

L'opérateur Logical OR ne fonctionne pas comme vous le souhaitez.

Renvoie expr1 si elle peut être convertie en true; Sinon, renvoie expr2. Ainsi, lorsqu'il est utilisé avec des valeurs booléennes, || Renvoie true si l'un ou l'autre opérande est vrai; Si les deux sont faux, renvoie faux.

MDN

Une autre façon pourrait utiliser la méthode indexOf du tableau. Il suffit de savoir qu'il renverra l' index de l'élément du tableau, donc 0 pourrait également être une valeur valide. Pour que notre déclaration if fonctionne comme prévu, nous devons utiliser 0 <= ... comme ceci:

 if ( 0 <= ["apple","banana"].indexOf(a) ) { ... } 

L'autre chose que vous pouvez faire est d'utiliser in opérateur. Aussi, car il ne vérifie que les keys , vous pouvez laisser les values vides comme ceci:

 if ( a in { "apple": "", "banana": "" } ) { ... } 

Si vous avez beaucoup d'options, il est évident qu'il vaut mieux faire ce qui suit:

 var options = { "apple": "", "banana": "" } if ( a in options ) { ... } 

Personnellement, je pense qu'avec seulement deux options à vérifier, cela sera plus lisible pour un œil humain pour deux contrôles séparés, et je pense que dans vos exemples, vous n'avez pas vraiment besoin de raccourcir les énoncés if , car elles sont déjà assez Bref et lisible à mon avis.

 if ( "apple" === a || "banana" === a ) { ... } 

Si vous voulez un moyen propre de vérifier si une variable est égale à un certain nombre d'autres variables, essayez d'utiliser une fonction comme celle-ci:

http://jsfiddle.net/aYRmL/

 function equalsAny (first) { return !![].slice.call(arguments, 1).filter(function (val) { return first === val; }).length; } 

Le premier argument est celui comparé au reste. Utilisez-le comme ceci:

 var a = 'banana', b = 'orange'; equalsAny(a, 'banana', 'apple'); // returns true equalsAny('orange', a, b); // returns true 

Le premier ci-dessus accomplit ce que vous essayez de faire avec a == ('banana' || 'apple') . Les secondes accomplissent ce que vous essayez de faire avec (a || b) == 'banana' .

En tant que solution alternative, vous pouvez utiliser some ou every :

 var __slice = [].slice; function any(a) { return __slice.call(arguments,1).some(function(x) { return a === x; }); } function all(a) { return __slice.call(arguments,1).every(function(x) { return a === x; }); } 

Et utiliser comme:

 // Instead of: // if (a == 'banana' || a == 'apple' || a == 'orange') if (any(a, 'banana', 'apple', 'orange')) { ... } // Instead of: // if (a == 'banana' && b == 'banana' && c == 'banana') if (all('banana', a, b, c)) { ... } 

(a || b) == 'banana' sera toujours faux parce que (a || b) renverra une sorcière booléenne qui ne correspond pas à une chaîne

MISE À JOUR: certains essais (a || b) renvoient toujours le premier opérande ( a dans ce cas) qui est «pomme» et non égal à «banane».

|| Et && donnera un résultat exceptionnel uniquement si les deux opérandes sont booléens ou peuvent être encastrés en booléen.

La façon dont il fonctionne est que a && b et a || b a || b sont toujours définis sur la valeur d'une des variables. a && b sera toujours réglé sur la valeur de b moins a soit false , auquel cas la réponse doit être false . De même, a || b a || b sera réglé sur la valeur de a , à moins a soit false , auquel cas il sera défini sur la valeur de b . Comme l'ont mentionné elclanrs, cela s'explique par une évaluation de court-circuit: le premier opérande peut déterminer le résultat, auquel cas il est inutile de regarder le second opérande.

Lorsque a et b sont des chaînes, elles ne seront jamais fausses, à moins que la chaîne ne soit nulle. Donc a || b a || b sera «Apple» dans votre cas, et a && b sera «banane».