为什么没有逻辑异或运算符?

287
为什么JavaScript中没有逻辑的XOR运算符?
21个回答

4

布尔值的一行代码:

if (x ? !y : y) { do something cool }

4
为了后人着想,也因为我发现这是一个不错的练习,你可以很容易地利用XOR运算符和truthiness来强制转换。与所选答案一样,这可能有点太聪明了。
const xor = (a, b) => !!(!!a ^ !!b)

console.log(undefined ^ {}) // Returns 0, bitwise can't be done here.
console.log(xor(undefined, {})) // Returns true, because {} is truthy and undefined is falsy
console.log(0 ^ 1) // Works naturally, returns 1
console.log(xor(0, 1)) // Also works, returns true
console.log(true ^ false) // Again, returns true
console.log(xor(true, false)) // And again, returns true...

为了好玩,这应该可以在TypeScript中工作,通过强制使用明确的 any 类型:

const xor = (a: any, b: any) => !!((!!a as any) ^ (!!b as any))

1
爱死这个回答了 :) - Barry Michael Doyle

2
在上面的异或函数中,它会产生与逻辑异或不完全相同的类似结果,这意味着它将考虑数据类型匹配,并产生"对于相等的值为false""对于不同的值为true"
此异或函数将作为实际的异或或逻辑运算符工作,这意味着根据传递的值是真值还是假值,它将产生true或false。根据您的需求使用。
function xor(x,y){return true==(!!x!==!!y);}

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

"xnor" 等同于 "==="。 - daniel1426
@daniel1426 不完全正确。它与 (!!x) === (!!y) 相同。区别在于将其转换为布尔值。'' === 0 是假的,而 xnor('', 0) 是真的。 - tschwab

2
没有逻辑异或(^^)的原因是,与&&和||不同,它不会提供任何懒惰逻辑优势。也就是说,右侧和左侧表达式的状态都必须被评估。

2

在 TypeScript 中(+ 变为数字值):

value : number = (+false ^ +true)

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

在普通的JavaScript中,!!(false ^ true)可以正常使用布尔值。但在TypeScript中,需要加上+才能使其有效:!!(+false ^ +true) - pfg

0

cond1 xor cond2 等价于 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])}`)
}


为了使这个证明在现实世界中有意义,我建议修改值以接受任何真/假值,而不仅仅是布尔值:function xor(cond1, cond2){ return !!cond1 + !!cond2 === 1 } - Chris Perry
@ChrisPerry 我理解你的建议。但是我的答案是关于XOR的概念,它处理布尔实体。使用真值比较会导致混淆不应该混淆的概念。这是个人选择,我更喜欢将我的答案范围限制在布尔值上。 - madjaoue
JavaScript 的整个意义不就是应该混合使用 truthy 表示法吗? - Chris Perry

0
很多人讨论为什么这不可用,以及其他方法。我想要关注的是如何使其易于理解/维护,并且易于扩展到一组值(数组); 为此:
[true, false].filter(x => x).length === 1;         // true, only 1 truthy
[false, true, false].filter(x => x).length === 1;  // true, only 1 truthy
[true, false, true].filter(x => x).length === 1;   // false, 2+ truthy

利用数组的filter和length成员,可以轻松地嵌入到代码中。或者,也可以将其封装成一个可重复使用的函数,以下是示例用法:
function xor(array) {
    return (array ?? []).filter(x => x).length === 1;
}

xor([true, false]);         // true, only 1 truthy
xor([false, true, false]);  // true, only 1 truthy
xor([true, false, true]);   // false, 2+ truthy

-1

以下是一种使用2个或更多变量并提供计数奖励的备选解决方案。

这里有一个更通用的解决方案,可以模拟逻辑异或操作符的任何真假值,就像在标准IF语句中一样:

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!` );

我喜欢这个的原因是它也回答了“这些变量中有多少是真值?”所以我通常会预先存储这个结果。
对于那些想要严格的布尔值-TRUE异或检查行为的人,只需执行以下操作:
if( ( ( v1===true ) + ( v2===true ) + ( v3===true ) + ( v4===true ) + ( v5===true ) ) === 1 )
  // etc.

如果您不关心计数,或者如果您关心最佳性能:那么只需对强制转换为布尔值的值使用按位异或运算符,以获得真/假解决方案:

if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
  // etc.

-1

这里提出的大多数方法都很难阅读和理解。与其编写一些神秘的比较或试图对它们进行注释,不如定义一个可重复使用且自我解释的函数:

function either(a: boolean, b: boolean): boolean {
  return (a !== b);
}

或者更通用的一个:

function either(a: any, b: any): boolean {
  return Boolean(a) !== Boolean(b);
}

然后你可以像这样使用它:

assert(either(one, another), 'Either one or another, not both');

-2

嘿,我找到了一个解决方案,在JavaScript和TypeScript上进行XOR操作。

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
}

虽然这个解决方案可行,但它绝对是所有答案中最不易读的,因为有那么多神秘的符号。我宁愿看到在评论中写的语句被转化成代码。 - Lajos Mészáros
这个解决方案有点过于复杂,没有任何实际的收益。一元加号只是多余和不必要的,因为一个单独的 ! 符号已经将操作数转换为布尔值。这意味着所有 + 做的就是将 truefalse 转换为 10,在这种情况下两者产生的结果都是相同的。同时也值得注意的是,!!a ^ !!b 等价于 !a ^ !b - zcoop98

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接