Perché non c'è xor logico in JavaScript?
Perché non c'è xor logico in JavaScript?
Risposte:
JavaScript fa risalire la sua origine a C e C non ha un operatore XOR logico. Principalmente perché non è utile. Bitwise XOR è estremamente utile, ma in tutti i miei anni di programmazione non ho mai avuto bisogno di un XOR logico.
Se hai due variabili booleane puoi simulare XOR con:
if (a != b)
Con due variabili arbitrarie è possibile utilizzare !
per forzarli a valori booleani e quindi utilizzare lo stesso trucco:
if (!a != !b)
È piuttosto oscuro e meriterebbe sicuramente un commento. In effetti, potresti persino usare l'operatore XOR bit per bit a questo punto, anche se questo sarebbe troppo intelligente per i miei gusti:
if (!a ^ !b)
Javascript ha un operatore XOR bit a bit: ^
var nb = 5^9 // = 12
Puoi usarlo con booleani e darà il risultato come 0 o 1 (che puoi riconvertire in booleano, ad es result = !!(op1 ^ op2)
.). Ma come ha detto John, è equivalente a result = (op1 != op2)
, che è più chiaro.
true^true
è 0 ed false^true
è 1.
||
e &&
può essere utilizzato come operatore logico su 5 || 7
valori non booleani (ad es. restituisce un valore di verità, "bob" && null
restituisce un valore di falsa) ma ^
non può. Ad esempio, 5 ^ 7
uguale a 2, che è vero.
(true ^ false) !== true
che lo rende fastidioso con le librerie che richiedono veri e propri booleani
a ^= true
toggle booleani e non funziona su alcune macchine come i telefoni.
Non ci sono veri e propri operatori logici booleani in Javascript (sebbene !
si avvicini abbastanza). Un operatore logico prenderebbe solo true
o false
come operandi e ritornerebbe solo true
o false
.
In Javascript &&
e ||
prendere tutti i tipi di operandi e restituire tutti i tipi di risultati divertenti (qualunque cosa si alimenterà di loro).
Inoltre, un operatore logico dovrebbe sempre tenere conto dei valori di entrambi gli operandi.
In Javascript &&
e ||
prendere una scorciatoia pigri e non valutare il secondo operando in alcuni casi e, quindi, trascurare i suoi effetti collaterali. Questo comportamento è impossibile da ricreare con un xor logico.
a() && b()
valuta a()
e restituisce il risultato se è falso. Altrimenti valuta b()
e restituisce il risultato. Pertanto, il risultato restituito è veritiero se entrambi i risultati sono veritieri e falsa in caso contrario.
a() || b()
valuta a()
e restituisce il risultato se è vero. Altrimenti valuta b()
e restituisce il risultato. Pertanto, il risultato restituito è falso se entrambi i risultati sono falsi e verità in caso contrario.
Quindi l'idea generale è di valutare prima l'operando di sinistra. L'operando giusto viene valutato solo se necessario. E l'ultimo valore è il risultato. Questo risultato può essere qualsiasi cosa. Oggetti, numeri, stringhe .. qualunque cosa!
Questo rende possibile scrivere cose come
image = image || new Image(); // default to a new Image
o
src = image && image.src; // only read out src if we have an image
Ma il valore di verità di questo risultato può anche essere usato per decidere se un operatore logico "reale" sarebbe tornato vero o falso.
Questo rende possibile scrivere cose come
if (typeof image.hasAttribute === 'function' && image.hasAttribute('src')) {
o
if (image.hasAttribute('alt') || image.hasAttribute('title')) {
Ma un operatore xor "logico" ( ^^
) dovrebbe sempre valutare entrambi gli operandi. Ciò lo differenzia dagli altri operatori "logici" che valutano il secondo operando solo se necessario. Penso che sia per questo che non c'è xor "logico" in Javascript, per evitare confusione.
Quindi cosa dovrebbe succedere se entrambi gli operandi sono falsi? Entrambi potrebbero essere restituiti. Ma solo uno può essere restituito. Quale? Il primo? O il secondo? La mia intuizione mi dice di restituire i primi ma di solito gli operatori "logici" valutano da sinistra a destra e restituiscono l'ultimo valore valutato. O forse un array contenente entrambi i valori?
E se un operando è veritiero e l'altro operando è falso, un xor dovrebbe restituire quello sincero. O forse un array contenente quello vero, per renderlo compatibile con il caso precedente?
E infine, cosa dovrebbe succedere se entrambi gli operandi sono veri? Ti aspetteresti qualcosa di falso. Ma non ci sono risultati falsi. Quindi l'operazione non dovrebbe restituire nulla. Quindi forse undefined
o ... un array vuoto? Ma un array vuoto è ancora vero.
Adottando l'approccio array dovresti finire con condizioni come if ((a ^^ b).length !== 1) {
. Molto confuso.
Converti i valori in forma booleana, quindi prendi XOR bit a bit. Aiuterà anche con valori non booleani.
Boolean(a) ^ Boolean(b)
c'è ... sorta di:
if( foo ? !bar : bar ) {
...
}
o più facile da leggere:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
perché? Boh.
perché gli sviluppatori javascript hanno pensato che non sarebbe necessario in quanto può essere espresso da altri operatori logici, già implementati.
potresti anche avere solo gon con nand e questo è tutto, puoi impressionare ogni altra possibile operazione logica da quello.
personalmente penso che abbia ragioni storiche che derivano da linguaggi di sintassi basati su c, dove per quanto ne so xor non è presente o almeno estremamente raro.
Sì, basta fare quanto segue. Supponendo che tu abbia a che fare con i booleani A e B, il valore A XOR B può essere calcolato in JavaScript usando il seguente
var xor1 = !(a === b);
La riga precedente equivale anche alla seguente
var xor2 = (!a !== !b);
Personalmente, preferisco xor1 poiché devo digitare meno caratteri. Credo che anche xor1 sia anche più veloce. Sta solo eseguendo due calcoli. xor2 sta eseguendo tre calcoli.
Spiegazione visiva ... Leggi la tabella qui sotto (dove 0 sta per falso e 1 sta per vero) e confronta la 3a e la 5a colonna.
! (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 |
------------------------------------------
Godere.
var xor1 = !(a === b);
è lo stesso divar xor1 = a !== b;
!(2 === 3)
è true
, ma 2
e 3
sono truthy così 2 XOR 3
dovrebbe essere false
.
Check-out:
Puoi imitare qualcosa del genere:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
Che ne dite di trasformare il risultato int a un bool con doppia negazione? Non così carino, ma davvero compatto.
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);
Inoltre, perché così tante parentesi? B = !state1 !== !state2;
Oppure puoi persino abbandonare la negazione:B = state1 !== state2;
state1 !== state2
, allora non è necessario eseguire alcun casting lì, poiché !==
è un operatore logico, non bit a bit. 12 !== 4
è vero 'xy' !== true
è anche vero. Se dovessi usare !=
invece di !==
, allora dovresti fare il casting.
!==
ed !=
è sempre booleano ... non sono sicuro di quale sia la distinzione che stai facendo, non è assolutamente il problema. Il problema è che l'operatore XOR che vogliamo è davvero l'espressione (Boolean(state1) !== Boolean(state2))
. Per i booleani, "xy", 12, 4 e true
sono tutti valori di verità, e dovrebbero convertirsi in true
. così ("xy" XOR true)
dovrebbe essere false
, ma ("xy" !== true)
è invece true
, come fai notare. Quindi !==
o !=
sono (entrambi) equivalenti a "XOR logico" se e solo se convertite i loro argomenti in booleani prima dell'applicazione.
Nella precedente funzione xor si otterrà un risultato SIMILE in quanto xor logico non esattamente xor logico, significa che risulterà "falso per valori uguali" e "vero per valori diversi" tenendo conto della corrispondenza del tipo di dati.
Questa funzione xor funzionerà come vero xor o operatore logico , significa che risulterà vero o falso secondo che i valori di passaggio sono veritieri o falsi . Utilizzare in base alle proprie esigenze
function xor(x,y){return true==(!!x!==!!y);}
function xnor(x,y){return !xor(x,y);}
(!!x) === (!!y)
. La differenza è un cast booleano. '' === 0
è falso, mentre xnor('', 0)
è vero.
In Typescript (Il + cambia in valore numerico):
value : number = (+false ^ +true)
Così:
value : boolean = (+false ^ +true) == 1
!!(false ^ true)
funziona bene con i booleani. In dattiloscritto, + è necessario per renderlo valido !!(+false ^ +true)
.
cond1 xor cond2
è equivalente a cond1 + cond 2 == 1
:
Ecco la prova:
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])}`)
}
Il motivo per cui non esiste un XOR logico (^^) è perché a differenza di && e || non offre alcun vantaggio logico. Questo è lo stato di entrambe le espressioni a destra e a sinistra che devono essere valutate.
Ecco una soluzione alternativa che funziona con 2+ variabili e fornisce il conteggio come bonus.
Ecco una soluzione più generale per simulare XOR logico per qualsiasi valore di verità / falsità, proprio come se avessi l'operatore in istruzioni 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!` );
Il motivo per cui mi piace questo è perché risponde anche "Quante di queste variabili sono veritiere?", Quindi di solito pre-memorizzo quel risultato.
E per coloro che desiderano un comportamento booleano-TRUE xor check rigoroso, basta fare:
if( ( ( v1===true ) + ( v2===true ) + ( v3===true ) + ( v4===true ) + ( v5===true ) ) === 1 )
// etc.
Se non ti interessa il conteggio o se ti preoccupi delle prestazioni ottimali: usa semplicemente lo xor bit a bit sui valori forzati a booleani, per la soluzione verità / falsa:
if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
// etc.
Ehi, ho trovato questa soluzione, per creare e XOR su JavaScript e 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
}
Prova questo breve e facile da capire
function xor(x,y){return true==(x!==y);}
function xnor(x,y){return !xor(x,y);}
Funzionerà con qualsiasi tipo di dati
true == someboolean
non è necessario, quindi in realtà ciò che hai fatto è avvolgere i rigidi non uguali in una funzione.
!=
è che non puoi fare lo stessoa ^= b
, perchéa !== b
è solo l' operatore di disuguaglianza rigorosa .