web-dev-qa-db-fra.com

Pourquoi n'y a-t-il pas de xor logique en JavaScript?

Pourquoi n'y a-t-il pas de xor logique en JavaScript?

177
DarkLightA

JavaScript retrace ses origines en C, et C n'a pas d'opérateur logique XOR. Principalement parce que ce n'est pas utile. Bitwise XOR est extrêmement utile, mais toutes mes années de programmation, je n'ai jamais eu besoin d'un XOR logique.

Si vous avez deux variables booléennes, vous pouvez imiter XOR avec:

if (a != b)

Avec deux variables arbitraires, vous pouvez utiliser ! pour les contraindre à des valeurs booléennes et utiliser ensuite le même truc:

if (!a != !b)

C'est assez obscur cependant et mériterait certainement un commentaire. En effet, vous pouvez même utiliser l’opérateur bitwise XOR à ce stade, bien que ce soit beaucoup trop intelligent à mon goût:

if (!a ^ !b)
339
John Kugelman

Javascript a un bitwise XOR opérateur: ^

var nb = 5^9 // = 12

Vous pouvez l'utiliser avec des booléens et le résultat sera 0 ou 1 (que vous pourrez reconvertir en booléen, par exemple result = !!(op1 ^ op2)). Mais comme John l'a dit, cela équivaut à result = (op1 != op2), ce qui est plus clair.

75
Pikrass

Il n'y a pas de véritables opérateurs logiques booléens en Javascript (bien que ! Soit assez proche). Un opérateur logique ne prendrait que true ou false comme opérandes et ne renverrait que true ou false.

En Javascript && Et || Prennent toutes sortes d'opérandes et renvoient toutes sortes de résultats amusants (tout ce que vous y introduisez).

De plus, un opérateur logique doit toujours prendre en compte les valeurs des deux opérandes.

En Javascript && Et || Prenez un raccourci paresseux et faites ne pas évaluer le second opérande dans certains cas et négligez ainsi ses effets secondaires. Ce comportement est impossible à recréer avec un xor logique.


a() && b() évalue a() et renvoie le résultat s'il est faux. Sinon, il évalue b() et renvoie le résultat. Par conséquent, le résultat renvoyé est la vérité si les deux résultats sont la vérité et la fausseté sinon.

a() || b() évalue a() et renvoie le résultat s'il est vrai. Sinon, il évalue b() et renvoie le résultat. Par conséquent, le résultat renvoyé est faux si les deux résultats sont faux, et la vérité sinon.

L'idée générale est donc d'évaluer l'opérande de gauche en premier. Le bon opérande n'est évalué que si nécessaire. Et la dernière valeur est le résultat. Ce résultat peut être n'importe quoi. Objets, nombres, ficelles… peu importe!

Cela permet d’écrire des choses comme

image = image || new Image(); // default to a new Image

ou

src = image && image.src; // only read out src if we have an image

Mais la valeur de vérité de ce résultat peut également être utilisée pour décider si un opérateur logique "réel" serait retourné vrai ou faux.

Cela permet d’écrire des choses comme

if (typeof image.hasAttribute === 'function' && image.hasAttribute('src')) {

ou

if (image.hasAttribute('alt') || image.hasAttribute('title')) {

Mais un opérateur xor "logique" (^^) Devra toujours évaluer les deux opérandes. Cela le différencie des autres opérateurs "logiques" qui évaluent le second opérande uniquement si nécessaire. Je pense que c'est pourquoi il n'y a pas de "logique" xor en Javascript, pour éviter toute confusion.


Alors, que devrait-il se passer si les deux opérandes sont faux? Les deux pourraient être retournés. Mais un seul peut être retourné. Laquelle? Le premier? Ou le second? Mon intuition me dit de renvoyer le premier, mais généralement les opérateurs "logiques" évaluent de gauche à droite et renvoient la dernière valeur évaluée. Ou peut-être un tableau contenant les deux valeurs?

Et si un des opérandes est la vérité et que l’autre est de la fausseté, un xor devrait retourner le vrai. Ou peut-être un tableau contenant la vérité, pour le rendre compatible avec le cas précédent?

Et enfin, que devrait-il se passer si les deux opérandes sont la vérité? Vous vous attendriez à quelque chose de faux. Mais il n'y a pas de résultats de fausseté. Donc, l'opération ne devrait rien renvoyer. Alors peut-être que undefined ou .. un tableau vide? Mais un tableau vide est toujours la vérité.

En adoptant l'approche tableau, vous vous retrouveriez avec des conditions telles que if ((a ^^ b).length !== 1) {. Très perturbant.

28
Robert

Le XOR de deux booléens est simplement s'ils sont différents, donc:

Boolean(a) !== Boolean(b)
11
DomQ

il y a ... en quelque sorte:

if( foo ? !bar : bar ) {
  ...
}

ou plus facile à lire:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}

pourquoi? ne sais pas.

parce que les développeurs javascript pensaient que ce serait inutile car cela peut être exprimé par d'autres opérateurs logiques déjà implémentés.

vous pourriez aussi bien avoir gon avec Nand et c'est tout, vous pouvez impressionner toutes les autres opérations logiques possibles à partir de cela.

je pense personnellement qu’il a des raisons historiques qui dérivent des langages de syntaxe basés sur c, où, à ma connaissance, xor n’est pas présent ou du moins, extrêmement rare.

9
The Surrican

Oui, faites juste ce qui suit. En supposant que vous traitiez avec les booléens A et B, alors la valeur de A XOR B peut être calculée en JavaScript à l’aide de ce qui suit:

var xor1 = !(a === b);

La ligne précédente est aussi équivalente à la suivante

var xor2 = (!a !== !b);

Personnellement, je préfère xor1 car je dois taper moins de caractères. Je pense que xor1 est également plus rapide. C'est juste faire deux calculs. xor2 effectue trois calculs.

Explication visuelle ... Lisez le tableau ci-dessous (où 0 correspond à faux et 1 à vrai) et comparez les 3ème et 5ème colonnes.

! (A === B):

| A | B | A XOR B | A === B | !(A === B) |
------------------------------------------
| 0 | 0 |    0    |    1    |      0     |
| 0 | 1 |    1    |    0    |      1     |
| 1 | 0 |    1    |    0    |      1     |
| 1 | 1 |    0    |    1    |      0     |
------------------------------------------

Prendre plaisir.

7
asiby

Convertir en booléen puis effectuer xor comme -

!!a ^ !!b
6
toyeca

Convertissez les valeurs en forme booléenne, puis prenez XOR au niveau du bit. Cela aidera également avec les valeurs non booléennes.

Boolean(a) ^ Boolean(b)
5
Aman Kaushal

Check-out:

Vous pouvez imiter quelque chose comme ça:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}
4
Sarfraz

Pourquoi ne pas transformer le résultat int en bool avec double négation? Pas si joli, mais vraiment compact.

var state1 = false,
    state2 = true;
    
var A = state1 ^ state2;     // will become 1
var B = !!(state1 ^ state2); // will become true
console.log(A);
console.log(B);
4
Lajos Meszaros

Dans la fonction xor ci-dessus, il en résultera SIMILAIRE résultat comme xor logique ne signifie pas exactement xor logique, cela signifie "false pour des valeurs égales" et "true pour différentes valeurs" avec correspondance du type de données.

Cette fonction xor fonctionnera comme xor ou opérateur logique, signifie que le résultat sera vrai ou faux, selon les valeurs transmises: vérité ou falsy. Utilisez selon vos besoins

function xor(x,y){return true==(!!x!==!!y);}

function xnor(x,y){return !xor(x,y);}
2
Premchandra Singh

Vous utilisez le fait que cond1 xor cond2 est équivalent à cond1 + cond 2 == 1:

let ops = [[false, false],[false, true], [true, false], [true, true]];

function xor(cond1, cond2){
  return cond1 + cond2 == 1;
}

for(op of ops){
  console.log(`${op[0]} xor ${op[1]} is ${xor(op[0], op[1])}`)
}
1
madjaoue

In TypeScript (Le + change en valeur numérique):

value : number = (+false ^ +true)

Alors:

value : boolean = (+false ^ +true) == 1
0
Witold Kaczurba

La raison pour laquelle il n’ya pas de logique XOR (^^) est que, contrairement à && et ||, cela ne donne aucun avantage en logique de paresse. C’est l’état des deux expressions à droite et à gauche Pour être évalué.

0
user7163886