¿Por qué no hay xor lógico en JavaScript?
¿Por qué no hay xor lógico en JavaScript?
Respuestas:
JavaScript rastrea su ascendencia hasta C, y C no tiene un operador XOR lógico. Principalmente porque no es útil. Bitwise XOR es extremadamente útil, pero en todos mis años de programación nunca he necesitado un XOR lógico.
Si tiene dos variables booleanas, puede imitar XOR con:
if (a != b)
Con dos variables arbitrarias que podría usar !
para obligarlos a valores booleanos y luego usar el mismo truco:
if (!a != !b)
Sin embargo, eso es bastante oscuro y sin duda merecería un comentario. De hecho, incluso podría usar el operador XOR bit a bit en este punto, aunque esto sería demasiado inteligente para mi gusto:
if (!a ^ !b)
Javascript tiene un operador XOR bit a bit: ^
var nb = 5^9 // = 12
Puede usarlo con booleanos y dará el resultado como 0 o 1 (que puede convertir de nuevo a booleano, por ejemplo result = !!(op1 ^ op2)
). Pero como dijo John, es equivalente a result = (op1 != op2)
, que es más claro.
true^true
es 0 y false^true
es 1.
||
y &&
puede usarse como operadores lógicos en no booleanos (por ejemplo, 5 || 7
devuelve un valor verdadero, "bob" && null
devuelve un valor falsey) pero ^
no puede. Por ejemplo, 5 ^ 7
es igual a 2, que es verdad.
(true ^ false) !== true
lo que lo hace molesto con las bibliotecas que requieren booleanos reales
a ^= true
alternar booleanos y falla en algunas máquinas como los teléfonos.
No hay operadores booleanos lógicos reales en Javascript (aunque se !
acerca bastante). Un operador lógico solo tomaría true
o false
como operandos y solo devolvería true
o false
.
En Javascript &&
y ||
tomar todo tipo de operandos y devolver todo tipo de resultados divertidos (lo que sea que se introduce en ellos).
Además, un operador lógico siempre debe tener en cuenta los valores de ambos operandos.
En Javascript &&
y ||
tomar un atajo perezoso y no evaluar el segundo operando en ciertos casos y con ello el abandono de sus efectos secundarios. Este comportamiento es imposible de recrear con un xor lógico.
a() && b()
evalúa a()
y devuelve el resultado si es falso. De lo contrario, evalúa b()
y devuelve el resultado. Por lo tanto, el resultado devuelto es verdadero si ambos resultados son verdaderos y falso de lo contrario.
a() || b()
evalúa a()
y devuelve el resultado si es verdadero. De lo contrario, evalúa b()
y devuelve el resultado. Por lo tanto, el resultado devuelto es falso si ambos resultados son falsos y, en caso contrario, verdadero.
Entonces, la idea general es evaluar primero el operando izquierdo. El operando correcto solo se evalúa si es necesario. Y el último valor es el resultado. Este resultado puede ser cualquier cosa. Objetos, números, cadenas ... ¡lo que sea!
Esto hace posible escribir cosas como
image = image || new Image(); // default to a new Image
o
src = image && image.src; // only read out src if we have an image
Pero el valor de verdad de este resultado también se puede utilizar para decidir si un operador lógico "real" habría devuelto verdadero o falso.
Esto hace posible escribir cosas como
if (typeof image.hasAttribute === 'function' && image.hasAttribute('src')) {
o
if (image.hasAttribute('alt') || image.hasAttribute('title')) {
Pero un operador xor "lógico" ( ^^
) siempre tendría que evaluar ambos operandos. Esto lo hace diferente a los otros operadores "lógicos" que evalúan el segundo operando solo si es necesario. Creo que es por eso que no hay xor "lógico" en Javascript, para evitar confusiones.
Entonces, ¿qué debería pasar si ambos operandos son falsos? Ambos podrían ser devueltos. Pero solo uno puede ser devuelto. ¿Cúal? ¿El primero? O el segundo? Mi intuición me dice que devuelva los primeros, pero generalmente los operadores "lógicos" evalúan de izquierda a derecha y devuelven el último valor evaluado. ¿O tal vez una matriz que contiene ambos valores?
Y si un operando es verdadero y el otro operando es falso, un xor debería devolver el verdadero. ¿O tal vez una matriz que contiene el verdadero, para que sea compatible con el caso anterior?
Y finalmente, ¿qué debería pasar si ambos operandos son verdaderos? Esperarías algo falso. Pero no hay resultados falsos. Entonces la operación no debería devolver nada. Entonces tal vez undefined
o ... ¿una matriz vacía? Pero una matriz vacía sigue siendo verdadera.
Tomando el enfoque de matriz, terminaría con condiciones como if ((a ^^ b).length !== 1) {
. Muy confuso.
Convierta valores en forma booleana y luego tome XOR bit a bit. También ayudará con valores no booleanos.
Boolean(a) ^ Boolean(b)
hay ... una especie de:
if( foo ? !bar : bar ) {
...
}
o más fácil de leer:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
¿por qué? No sé.
porque los desarrolladores de JavaScript pensaron que sería innecesario ya que puede ser expresado por otros operadores lógicos ya implementados.
también podría tener gon con nand y eso es todo, puede impresionar cualquier otra operación lógica posible a partir de eso.
Personalmente, creo que tiene razones históricas que se basan en lenguajes de sintaxis basados en c, donde, por lo que sé, xor no está presente o al menos es extremadamente raro.
Sí, solo haz lo siguiente. Suponiendo que se trata de booleanos A y B, el valor de A XOR B se puede calcular en JavaScript utilizando lo siguiente
var xor1 = !(a === b);
La línea anterior también es equivalente a la siguiente
var xor2 = (!a !== !b);
Personalmente, prefiero xor1 ya que tengo que escribir menos caracteres. Creo que xor1 también es más rápido también. Solo está realizando dos cálculos. xor2 está realizando tres cálculos.
Explicación visual ... Lea la tabla a continuación (donde 0 representa falso y 1 representa verdadero) y compare las columnas 3 y 5.
! (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 |
------------------------------------------
Disfrutar.
var xor1 = !(a === b);
es lo mismo quevar xor1 = a !== b;
!(2 === 3)
es true
, pero 2
y 3
son sinceros, así 2 XOR 3
debería ser false
.
Revisa:
Puedes imitarlo de esta manera:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
¿Qué tal transformar el resultado int en un bool con doble negación? No tan bonito, pero realmente compacto.
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);
Además, ¿por qué tantos paréntesis? B = !state1 !== !state2;
O incluso puede abandonar la negación:B = state1 !== state2;
state1 !== state2
, entonces no necesita hacer ninguna conversión allí, ya que !==
es un operador lógico, no un bit a bit. 12 !== 4
Es cierto 'xy' !== true
también es cierto. Si usarías en !=
lugar de !==
, entonces tendrías que hacer casting.
!==
y !=
siempre es booleano ... no estoy seguro de cuál es la distinción que estás haciendo allí, ese no es el problema. El problema es que el operador XOR que queremos es realmente la expresión (Boolean(state1) !== Boolean(state2))
. Para booleanos, "xy", 12, 4 y true
todos son valores verdaderos, y deben convertirse a true
. así ("xy" XOR true)
debería ser false
, pero en ("xy" !== true)
cambio true
, como usted señala. Entonces, !==
o !=
son (ambos) equivalentes a "XOR lógico" si y solo si convierte sus argumentos a booleanos antes de aplicar.
En la función xor anterior, se obtendrá un resultado SIMILAR ya que xor lógico no es exactamente xor lógico, significa que resultará "falso para valores iguales" y "verdadero para valores diferentes" teniendo en cuenta la coincidencia de tipos de datos.
Esta función xor funcionará como xor real u operador lógico , lo que significa que resultará verdadero o falso de acuerdo con los valores de paso verdaderos o falsos . Use de acuerdo a sus necesidades
function xor(x,y){return true==(!!x!==!!y);}
function xnor(x,y){return !xor(x,y);}
(!!x) === (!!y)
. La diferencia es un elenco a booleano. '' === 0
es falso, mientras que xnor('', 0)
es cierto.
En mecanografiado (el + cambia a valor numérico):
value : number = (+false ^ +true)
Entonces:
value : boolean = (+false ^ +true) == 1
!!(false ^ true)
funciona bien con booleanos. En mecanografiado, se requiere + para que sea válido !!(+false ^ +true)
.
cond1 xor cond2
es equivalente a cond1 + cond 2 == 1
:
Aquí está la prueba:
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 razón por la que no hay un XOR lógico (^^) es porque, a diferencia de && y || no da ninguna ventaja de lógica perezosa. Ese es el estado de ambas expresiones a la derecha y a la izquierda que deben evaluarse.
Aquí hay una solución alternativa que funciona con más de 2 variables y proporciona un recuento como bonificación.
Aquí hay una solución más general para simular XOR lógico para cualquier valor verdadero / falso, como si tuviera el operador en declaraciones IF estándar:
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 razón por la que me gusta esto es porque también responde "¿Cuántas de estas variables son verdaderas?", Por lo que generalmente guardo previamente ese resultado.
Y para aquellos que desean un estricto comportamiento booleano-VERDADERO o de verificación, simplemente haga:
if( ( ( v1===true ) + ( v2===true ) + ( v3===true ) + ( v4===true ) + ( v5===true ) ) === 1 )
// etc.
Si no le importa el recuento, o si le importa el rendimiento óptimo: simplemente use el xor bit a bit en los valores obligados a booleano, para la solución verdadero / falso:
if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
// etc.
Hola, encontré esta solución, para hacer y XOR en JavaScript y 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
}
Prueba este breve y fácil de entender
function xor(x,y){return true==(x!==y);}
function xnor(x,y){return !xor(x,y);}
Esto funcionará para cualquier tipo de datos.
true == someboolean
no es necesario hacerlo , así que realmente, lo que has hecho es envolver los estrictos no iguales en una función.
!=
es que no puedes hacer lo mismoa ^= b
, porquea !== b
es solo el operador de desigualdad estricta .