Pourquoi n'y a-t-il pas de xor logique en JavaScript?
Pourquoi n'y a-t-il pas de xor logique en JavaScript?
Réponses:
JavaScript fait remonter son ascendance à C et C n'a pas d'opérateur XOR logique. Principalement parce que ce n'est pas utile. Bitwise XOR est extrêmement utile, mais au cours de 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 les utiliser !
pour les contraindre à des valeurs booléennes, puis utiliser la même astuce:
if (!a != !b)
C'est assez obscur et mériterait certainement un commentaire. En effet, vous pouvez même utiliser l'opérateur XOR au niveau du bit à ce stade, bien que ce soit beaucoup trop intelligent à mon goût:
if (!a ^ !b)
Javascript a un opérateur XOR au niveau du bit: ^
var nb = 5^9 // = 12
Vous pouvez l'utiliser avec des booléens et il donnera le résultat sous forme de 0 ou 1 (que vous pouvez reconvertir en booléen, par exemple result = !!(op1 ^ op2)
). Mais comme John l'a dit, c'est équivalent à result = (op1 != op2)
, ce qui est plus clair.
true^true
est 0, et false^true
est 1.
||
et &&
peut être utilisé comme opérateurs logiques sur des non-booléens (par exemple, 5 || 7
renvoie une valeur de vérité, "bob" && null
renvoie une valeur de faux) mais ^
ne peut pas. Par exemple, 5 ^ 7
égal à 2, ce qui est vrai.
(true ^ false) !== true
ce qui le rend ennuyeux avec les bibliothèques qui nécessitent des booléens réels
a ^= true
pour basculer les booléens et cela échoue sur certaines machines telles que les téléphones.
Il n'y a pas de véritables opérateurs booléens logiques en Javascript (bien que cela !
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 ||
prenez toutes sortes d'opérandes et retournez toutes sortes de résultats amusants (tout ce que vous leur donnez).
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 n'évaluez pas le deuxième 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 véridique si les deux résultats sont véridiques et faux dans le cas contraire.
a() || b()
évalue a()
et renvoie le résultat s'il est véridique. 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 véridique dans le cas contraire.
L'idée générale est donc d'évaluer d'abord l'opérande gauche. L'opérande correct 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, chaînes ... 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" aurait 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" ( ^^
) devrait toujours évaluer les deux opérandes. Cela le rend différent des autres opérateurs "logiques" qui n'évaluent le deuxième opérande que si nécessaire. Je pense que c'est pourquoi il n'y a pas de xor "logique" 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» évalués de gauche à droite et renvoyer la dernière valeur évaluée. Ou peut-être un tableau contenant les deux valeurs?
Et si un opérande est vrai et que l'autre opérande est faux, un xor doit renvoyer celui qui est vrai. Ou peut-être un tableau contenant le vrai, pour le rendre compatible avec le cas précédent?
Et enfin, que devrait-il se passer si les deux opérandes sont véridiques? Vous vous attendriez à quelque chose de faux. Mais il n'y a pas de résultats erronés. L'opération ne doit donc rien renvoyer. Alors peut undefined
- être ou… un tableau vide? Mais un tableau vide est toujours vrai.
En adoptant l'approche par tableau, vous vous retrouveriez avec des conditions telles que if ((a ^^ b).length !== 1) {
. Très perturbant.
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)
il y a ... une sorte de:
if( foo ? !bar : bar ) {
...
}
ou plus facile à lire:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
Pourquoi? sais pas.
parce que les développeurs javascript pensaient que ce serait inutile car il 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 que cela a des raisons historiques qui découlent des langages de syntaxe basés sur c, où, à ma connaissance, xor n'est pas présent ou du moins extrêmement rare.
Oui, faites ce qui suit. En supposant que vous avez affaire aux booléens A et B, la valeur 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 également équivalente à la suivante
var xor2 = (!a !== !b);
Personnellement, je préfère xor1 car je dois taper moins de caractères. Je crois que xor1 est également plus rapide. Il s'agit simplement d'effectuer deux calculs. xor2 effectue trois calculs.
Explication visuelle ... Lisez le tableau ci-dessous (où 0 signifie faux et 1 signifie vrai) et comparez les 3e et 5e 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.
var xor1 = !(a === b);
est le même quevar xor1 = a !== b;
!(2 === 3)
est true
, mais 2
et 3
sont véridiques ainsi 2 XOR 3
devrait l'être false
.
Check-out:
Vous pouvez l'imiter quelque chose comme ceci:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
Que diriez-vous de transformer le résultat int en booléen 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);
B = ((!state1)!==(!state2))
B =!!(!state1 ^ !state2);
Aussi, pourquoi tant de parenthèses? B = !state1 !== !state2;
Ou vous pouvez même laisser tomber la négation:B = state1 !== state2;
state1 !== state2
, alors vous n'avez pas besoin de faire de transtypage là-bas, car il !==
s'agit d'un opérateur logique, pas d'un bit. 12 !== 4
est vrai 'xy' !== true
est également vrai. Si vous utilisiez à la !=
place de !==
, alors vous devrez faire du casting.
!==
et !=
est toujours booléen ... je ne sais pas quelle est la distinction que vous faites ici, ce n'est absolument pas le problème. Le problème est que l'opérateur XOR que nous voulons est vraiment l'expression (Boolean(state1) !== Boolean(state2))
. Pour les booléens, "xy", 12, 4 et true
sont toutes des valeurs de vérité et doivent être convertis en true
. ainsi ("xy" XOR true)
devrait être false
, mais ("xy" !== true)
est plutôt true
, comme vous le faites remarquer. Donc !==
ou !=
sont (les deux) équivalents à "XOR logique" si et seulement si vous convertissez leurs arguments en booléens avant d' appliquer.
Dans la fonction xor ci-dessus, il en résultera un résultat SIMILAIRE car xor logique ne correspond pas exactement à xor logique, ce qui signifie qu'il en résultera "faux pour des valeurs égales" et "vrai pour différentes valeurs" avec le type de données correspondant en considération.
Cette fonction xor fonctionnera comme un xor réel ou un opérateur logique , ce qui signifie qu'il en résultera vrai ou faux selon que les valeurs de passage sont vraies ou fausses . Utiliser selon vos besoins
function xor(x,y){return true==(!!x!==!!y);}
function xnor(x,y){return !xor(x,y);}
(!!x) === (!!y)
. La différence est une conversion en booléen. '' === 0
est faux, tandis que xnor('', 0)
est vrai.
Dans Typescript (le + change en valeur numérique):
value : number = (+false ^ +true)
Alors:
value : boolean = (+false ^ +true) == 1
!!(false ^ true)
fonctionne très bien avec les booléens. En dactylographié, + est nécessaire pour le rendre valide !!(+false ^ +true)
.
cond1 xor cond2
équivaut à cond1 + cond 2 == 1
:
Voici la preuve:
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])}`)
}
La raison pour laquelle il n'y a pas de XOR logique (^^) est que contrairement à && et || cela ne donne aucun avantage paresseux. C'est l'état des deux expressions à droite et à gauche qui doivent être évaluées.
Voici une solution alternative qui fonctionne avec plus de 2 variables et fournit un compte comme bonus.
Voici une solution plus générale pour simuler un XOR logique pour toutes les valeurs de vérité / faux, comme si vous aviez l'opérateur dans des instructions IF standard:
const v1 = true;
const v2 = -1; // truthy (warning, as always)
const v3 = ""; // falsy
const v4 = 783; // truthy
const v5 = false;
if( ( !!v1 + !!v2 + !!v3 + !!v4 + !!v5 ) === 1 )
document.write( `[ ${v1} XOR ${v2} XOR "${v3}" XOR ${v4} XOR ${v5} ] is TRUE!` );
else
document.write( `[ ${v1} XOR ${v2} XOR "${v3}" XOR ${v4} XOR ${v5} ] is FALSE!` );
La raison pour laquelle j'aime cela, c'est parce qu'elle répond également "Combien de ces variables sont véridiques?", Donc je pré-stocke généralement ce résultat.
Et pour ceux qui veulent un comportement de vérification strict booléen-TRUE xor, faites simplement:
if( ( ( v1===true ) + ( v2===true ) + ( v3===true ) + ( v4===true ) + ( v5===true ) ) === 1 )
// etc.
Si vous ne vous souciez pas du nombre, ou si vous vous souciez des performances optimales: utilisez simplement le xor au niveau du bit sur les valeurs forcées à booléen, pour la solution vérité / fausseté:
if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
// etc.
Hé j'ai trouvé cette solution, pour faire et XOR sur JavaScript et TypeScript.
if( +!!a ^ +!!b )
{
//This happens only when a is true and b is false or a is false and b is true.
}
else
{
//This happens only when a is true and b is true or a is false and b is false
}
Essayez ce court et facile à comprendre
function xor(x,y){return true==(x!==y);}
function xnor(x,y){return !xor(x,y);}
Cela fonctionnera pour tout type de données
true == someboolean
n'est pas nécessaire, donc vraiment, ce que vous avez fait, c'est envelopper les stricts non-égaux dans une fonction.
!=
est que vous ne pouvez pas faire la même chose quea ^= b
, cara !== b
c'est juste l' opérateur d' inégalité stricte .