242

为什么 JavaScript 中没有逻辑异或?

4

19 回答 19

398

JavaScript 将其祖先追溯到 C,而 C 没有逻辑 XOR 运算符。主要是因为没用。按位异或非常有用,但在我多年的编程生涯中,我从来不需要逻辑异或。

如果你有两个布尔变量,你可以模仿 XOR:

if (a != b)

您可以使用两个任意变量将!它们强制为布尔值,然后使用相同的技巧:

if (!a != !b)

不过,这非常晦涩难懂,当然值得评论。实际上,此时您甚至可以使用按位 XOR 运算符,尽管这对我来说太聪明了:

if (!a ^ !b)
于 2010-12-27T17:18:32.267 回答
83

Javascript 有一个按位异或运算符:^

var nb = 5^9 // = 12

您可以将它与布尔值一起使用,它会将结果显示为 0 或 1(您可以将其转换回布尔值,例如result = !!(op1 ^ op2))。但正如约翰所说,它相当于result = (op1 != op2),这更清楚。

于 2010-12-27T17:24:17.470 回答
31

Javascript 中没有真正的逻辑布尔运算符(尽管!非常接近)。逻辑运算符只会将trueorfalse作为操作数,并且只会返回trueor false

在 Javascript中&&||接受各种操作数并返回各种有趣的结果(无论你输入什么)。

此外,逻辑运算符应始终考虑两个操作数的值。

在 Javascript 中&&||采取惰性捷径,在某些情况下评估第二个操作数,从而忽略它的副作用。这种行为是不可能用逻辑异或重新创建的。


a() && b()如果结果是假的,则评估a()并返回结果。否则,它评估b()并返回结果。因此,如果两个结果都为真,则返回的结果为真,否则为假。

a() || b()如果结果为真,则评估a()并返回结果。否则,它评估b()并返回结果。因此,如果两个结果都为假,则返回的结果为假,否则为真。

所以一般的想法是首先评估左操作数。仅在必要时才评估正确的操作数。最后一个值是结果。这个结果可以是任何东西。对象,数字,字符串..随便!

这使得可以编写类似的东西

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

或者

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

但是这个结果的真值也可以用来决定一个“真正的”逻辑运算符是否会返回真或假。

这使得可以编写类似的东西

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

或者

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

但是“逻辑”异或运算符 ( ^^) 总是必须计算两个操作数。这使其与仅在必要时才评估第二个操作数的其他“逻辑”运算符不同。我认为这就是为什么 Javascript 中没有“逻辑”异或,以避免混淆。


那么如果两个操作数都是假的,会发生什么?两者都可以退货。但只能退回一个。哪一个?第一个?还是第二个?我的直觉告诉我返回第一个但通常是“逻辑”运算符从左到右评估并返回最后一个评估值。或者也许是一个包含两个值的数组?

如果一个操作数为真而另一个操作数为假,则异或应该返回真值。或者也许是一个包含真实数组的数组,以使其与前一种情况兼容?

最后,如果两个操作数都为真,会发生什么?你会期待一些虚假的东西。但是没有错误的结果。所以操作不应该返回任何东西。所以也许undefined或者..一个空数组?但是空数组仍然是真实的。

采用数组方法,您最终会遇到类似if ((a ^^ b).length !== 1) {. 非常混乱。

于 2012-03-14T13:23:32.277 回答
26

两个布尔值的异或只是它们是否不同,因此:

Boolean(a) !== Boolean(b)
于 2015-06-25T07:38:25.710 回答
16

将值转换为布尔形式,然后按位 XOR

Boolean(a) ^ Boolean(b) // === 0 | 1

请注意,此表达式的结果是数字不是布尔值。

按位异或也适用于非布尔值,但请记住,这是按位运算符,而不是逻辑运算符。使用非布尔值可能不会像您最初期望的那样:

(5 ^ 3) === 6 // true
于 2019-04-26T09:59:38.860 回答
12

隐蔽为布尔值,然后执行 xor 像 -

!!a ^ !!b
于 2019-04-26T09:39:05.273 回答
10

有……有点:

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

或更容易阅读:

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

为什么?不知道。

因为 javascript 开发人员认为它是不必要的,因为它可以由其他已经实现的逻辑运算符表示。

您也可以使用 nand ,仅此而已,您可以从中打动所有其他可能的逻辑操作。

我个人认为它有历史原因驱动基于 c 的语法语言,据我所知,xor 不存在或至少非常罕见。

于 2010-12-27T17:17:37.437 回答
7

是的,只需执行以下操作。假设您正在处理布尔值 A 和 B,那么 A XOR B 值可以在 JavaScript 中使用以下公式计算

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

上一行也等价于下面

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

就个人而言,我更喜欢 xor1,因为我必须输入更少的字符。我相信 xor1 也更快。它只是执行两个计算。xor2 正在执行三个计算。

视觉解释...阅读下表(其中 0 代表假,1 代表真)并比较第 3 列和第 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     |
------------------------------------------

享受。

于 2013-08-05T18:14:11.730 回答
5

查看:

你可以像这样模仿它:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}
于 2010-12-27T17:17:14.610 回答
4

如何将结果int转换为具有双重否定的布尔值?不是那么漂亮,但真的很紧凑。

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

于 2012-12-27T10:34:37.030 回答
4

布尔值的一个衬里:

if (x ? !y : y) { do something cool }
于 2020-09-04T15:24:47.493 回答
3

为了后代,并且因为我发现这是一个很好的练习,您可以很容易地利用 XOR 运算符的真实性来强制。就像选择的答案一样,它可能有点太聪明了。

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 中工作,通过强制显式任何:

const xor = (a: any, b: any) => !!((!!a as any) ^ (!!b as any))
于 2020-08-04T13:26:41.527 回答
2

在上面的异或函数中,它会产生类似的结果,因为逻辑异或不完全是逻辑异或,这意味着它将导致“相等值为假”“不同值为真”,并考虑数据类型匹配。

这个 xor 函数将作为实际的 xor 或逻辑运算符工作,这意味着它将根据传递的值是真还是假得出真假。根据您的需要使用

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

function xnor(x,y){return !xor(x,y);}
于 2013-08-08T08:07:07.000 回答
2

在 Typescript 中(+ 更改为数值):

value : number = (+false ^ +true)

所以:

value : boolean = (+false ^ +true) == 1
于 2019-01-08T20:57:38.540 回答
2

没有逻辑异或 (^^) 的原因是因为不像 && 和 || 它没有任何惰性逻辑优势。那就是必须评估左右两个表达式的状态。

于 2016-11-15T19:26:17.360 回答
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])}`)
}

于 2019-02-25T02:45:06.200 回答
-1

嘿,我找到了这个解决方案,可以在 JavaScript 和 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
}
于 2020-06-28T21:40:23.803 回答
-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!` );

我喜欢这个的原因是因为它还回答了“这些变量中有多少是真实的?”,所以我通常预先存储该结果。

对于那些想要严格的布尔真异或检查行为的人,只需执行以下操作:

if( ( ( v1===true ) + ( v2===true ) + ( v3===true ) + ( v4===true ) + ( v5===true ) ) === 1 )
  // etc.

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

if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
  // etc.
于 2020-05-26T22:45:44.603 回答
-3

试试这个简短易懂的

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

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

这适用于任何数据类型

于 2013-05-18T10:19:17.203 回答