Why is there no logical xor in JavaScript?

限于喜欢 提交于 2019-11-27 06:08:00

JavaScript traces its ancestry back to C, and C does not have a logical XOR operator. Mainly because it's not useful. Bitwise XOR is extremely useful, but in all my years of programming I have never needed a logical XOR.

If you have two boolean variables you can mimic XOR with:

if (a != b)

With two arbitrary variables you could use ! to coerce them to boolean values and then use the same trick:

if (!a != !b)

That's pretty obscure though and would certainly deserve a comment. Indeed, you could even use the bitwise XOR operator at this point, though this would be far too clever for my taste:

if (!a ^ !b)

Javascript has a bitwise XOR operator : ^

var nb = 5^9 // = 12

You can use it with booleans and it will give the result as a 0 or 1 (which you can convert back to boolean, e.g. result = !!(op1 ^ op2)). But as John said, it's equivalent to result = (op1 != op2), which is clearer.

There are no real logical boolean operators in Javascript (although ! comes quite close). A logical operator would only take true or false as operands and would only return true or false.

In Javascript && and || take all kinds of operands and return all kinds of funny results (whatever you feed into them).

Also a logical operator should always take the values of both operands into account.

In Javascript && and || take a lazy shortcut and do not evaluate the second operand in certain cases and thereby neglect its side effects. This behavior is impossible to recreate with a logical xor.


a() && b() evaluates a() and returns the result if it's falsy. Otherwise it evaluates b() and returns the result. Therefore the returned result is truthy if both results are truthy, and falsy otherwise.

a() || b() evaluates a() and returns the result if it's truthy. Otherwise it evaluates b() and returns the result. Therefore the returned result is falsy if both results are falsy, and truthy otherwise.

So the general idea is to evaluate the left operand first. The right operand only gets evaluated if necessary. And the last value is the result. This result can be anything. Objects, numbers, strings .. whatever!

This makes it possible to write things like

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

or

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

But the truth value of this result can also be used to decide if a "real" logical operator would have returned true or false.

This makes it possible to write things like

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

or

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

But a "logical" xor operator (^^) would always have to evaluate both operands. This makes it different to the other "logical" operators which evaluate the second operand only if necessary. I think this is why there is no "logical" xor in Javascript, to avoid confusion.


So what should happen if both operands are falsy? Both could be returned. But only one can be returned. Which one? The first one? Or the second one? My intuition tells me to return the first but usually "logical" operators evaluate from left to right and return the last evaluated value. Or maybe an array containing both values?

And if one operand is truthy and the other operand is falsy, an xor should return the truthy one. Or maybe an array containing the truthy one, to make it compatible with the previous case?

And finally, what should happen if both operands are truthy? You would expect something falsy. But there are no falsy results. So the operation shouldn't return anything. So maybe undefined or .. an empty array? But an empty array is still truthy.

Taking the array approach you would end up with conditions like if ((a ^^ b).length !== 1) {. Very confusing.

The XOR of two booleans is simply whether they are different, therefore:

Boolean(a) !== Boolean(b)

there is... sort of:

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

or easier to read:

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

why? dunno.

because javascript developers thought it would be unnecessary as it can be expressed by other, already implemented, logical operators.

you could as well just have gon with nand and thats it, you can impress every other possible logical operation from that.

i personally think it has historical reasons that drive from c-based syntax languages, where to my knowledge xor is not present or at least exremely uncommon.

Yes, Just do the following. Assuming that you are dealing with booleans A and B, then A XOR B value can be calculated in JavaScript using the following

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

The previous line is also equivalent to the following

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

Personally, I prefer xor1 since I have to type less characters. I believe that xor1 is also faster too. It's just performing two calculations. xor2 is performing three calculations.

Visual Explanation ... Read the table bellow (where 0 stands for false and 1 stands for true) and compare the 3rd and 5th columns.

!(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     |
------------------------------------------

Enjoy.

toyeca

Covert to boolean and then perform xor like -

!!a ^ !!b

Convert values into Boolean form then take bitwise XOR. It will help with non-boolean values as well.

Boolean(a) ^ Boolean(b)

Check out:

You can mimic it something like this:

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

How about transforming the result int to a bool with double negation? Not so pretty, but really 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);

In above xor function it will result SIMILAR result as logical xor does not exactly logical xor, means it will result "false for equal values" and "true for different values" with data type matching in consideration.

This xor function will work as actual xor or logical operator, means it will result true or false according to the passing values are truthy or falsy. Use according to your needs

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

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

You use the fact that cond1 xor cond2 is equivalent to 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])}`)
}

The reason there is no logical XOR (^^) is because unlike && and || it does not give any lazy-logic advantage. That is the state of both expressions on the right and left have to be evaluated.

In Typescript (The + changes to numeric value):

value : number = (+false ^ +true)

So:

value : boolean = (+false ^ +true) == 1

Try this short and easy to understand one

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

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

This will work for any data type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!