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


Answers:


358

JavaScript的祖先可以追溯到C,并且C没有逻辑XOR运算符。主要是因为它没有用。按位XOR极其有用,但是在我编程的所有岁月中,我从不需要逻辑XOR。

如果您有两个布尔变量,则可以使用以下方法模拟XOR:

if (a != b)

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

if (!a != !b)

但是,这非常晦涩,当然应该发表评论。确实,您甚至可以在此时使用按位XOR运算符,尽管这对我来说太聪明了:

if (!a ^ !b)

唯一的问题!=是您不能做与相同的操作a ^= b,因为a !== b它只是严格的不等式运算符。
mcpiroman

79

Javascript具有按位XOR运算符:^

var nb = 5^9 // = 12

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


28
那是按位XOR,不是逻辑XOR
Ismail Badawi 2010年

66
您可以将其用作逻辑异或。true^true是0,并且false^true是1
Pikrass

14
@Pikrass可以将其用作布尔值的逻辑运算符,但不能用于其他类型。||&&可用作非布尔值的逻辑运算符(例如,5 || 7返回真实值,"bob" && null返回伪值),但^不能。例如,5 ^ 7等于2,这是事实。
Mark Amery 2014年

9
@Pikrass但是,令人遗憾的是(true ^ false) !== true,这使需要实际布尔值的库变得烦人
Izkata 2014年

2
@Pikrass永远不要将其用作布尔值的逻辑运算符,因为实现取决于操作系统。我正在使用某种方式a ^= true来切换布尔值,但在某些机器(例如电话)上,它却失败了。
Masadow 2015年

30

Javascript中没有真正的逻辑布尔运算符(尽管!非常接近)。逻辑运算符只能采用truefalse作为操作数,并且只能返回truefalse

使用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

但是,此结果的真值也可以用于确定“真实”逻辑运算符是否返回true或false。

这样就可以编写类似

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

要么

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

但是“逻辑” xor运算符(^^)始终必须评估两个操作数。这使其不同于其他“逻辑”运算符,后者仅在必要时才对第二个操作数求值。我认为这就是为什么Javascript中没有“逻辑”异或运算以避免混淆的原因。


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

如果一个操作数是真实的,而另一个操作数是虚假的,则xor应该返回真实的一个。还是包含真值的数组,以使其与前面的情况兼容?

最后,如果两个操作数均为真该怎么办?你会期望一些虚假的东西。但是,没有虚假的结果。因此,该操作不应返回任何内容。那么,也许undefined还是..一个空数组?但是,空数组仍然是事实。

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


任何语言的XOR / ^^都必须同时评估两个操作数,因为它始终依赖于两者。AND / &&也是如此,因为所有操作数必须为true(在JS中为真)返回传递。例外是OR / || 因为它必须只求操作数,直到找到真实值为止。如果“或”列表中的第一个操作数为真,则不会评估其他任何一个。
Percy 2012年

但是,您确实指出,JS中的XOR必须打破AND和OR提出的约定。实际上,它必须返回一个正确的布尔值,而不是两个操作数之一。其他任何事情都可能引起混乱/复杂性。
Percy 2012年

9
如果第一个操作数为假,则@Percy AND / &&不评估第二个操作数。它只求操作数,直到找到虚假值为止。
罗伯特

@DDS感谢您纠正答案。我为自己为什么没注意到而感到困惑。也许这在一定程度上解释了珀西的困惑。
罗伯特

我的编辑被拒绝了,之后@matts完全按照我固定的方式对其进行了编辑,所以我(仅)错了2分。3个人拒绝了它,而我对他们使用的标准感到困惑。Thx亚光。
DDS

16

两个布尔值的XOR就是它们是否不同,因此:

Boolean(a) !== Boolean(b)


10

隐式转换为布尔值,然后执行xor,例如-

!!a ^ !!b

1
请注意,这!!a ^ !!b等效于!a ^ !b。可以争论哪个更容易阅读。
tschwab

9

有...一种:

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

或更容易阅读:

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

为什么?不知道。

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

您也可以仅将nand和gon结合起来,就可以从中打动其他所有可能的逻辑运算。

我个人认为,这是有历史原因的,其原因是基于C的语法语言,据我所知,xor不存在或至少极为罕见。


是的,javascript具有三元操作。
mwilcox

C和Java都使用^(脱字符号)字符进行XOR。
veidelis,2015年

7

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

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

上一行也等效于以下内容

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

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

视觉说明...阅读下表(其中0代表false,1代表true),然后比较第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     |
------------------------------------------

请享用。


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

此答案不适用于所有数据类型(例如Premchandra的答案)。例如!(2 === 3)true,但是23真实的2 XOR 3应该这样false
马里亚诺·德桑兹

2
如果您仔细阅读了我的信息,您会注意到我写了“假设您正在处理布尔A和B ...”。
asiby '16


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


如果操作数还不是布尔值,则将失败。更好的主意是B = ((!state1)!==(!state2))
Doin

是的,但是您始终可以否定操作数来强制转换它们,就像不确定类型一样:B =!!(!state1 ^ !state2); 为何还有这么多括号?B = !state1 !== !state2; 或者,您甚至可以放弃否定的条件:B = state1 !== state2;
Lajos

括号是为了清楚起见,因此在编写代码时,我不必检查运算符优先级的文档!;-)您的最后一个表达式遭受了我先前的抱怨:如果操作数不是布尔值,它将失败。但是,如果您确定它们是肯定的,那么它绝对是最简单,最快的“逻辑异或”表达式。
Doin

如果最后一个表达式的意思是state1 !== state2,那么您不需要在那里进行任何转换,因为!==它是逻辑运算符,而不是按位运算。12 !== 4是真的'xy' !== true也是如此。如果要使用!=而不是!==,则必须进行强制转换。
拉霍斯·梅萨罗斯

1
共同作用的结果!==,并!=始终是布尔......不知道你正在做的区别有应该是,这是绝对没有问题的。问题是我们想要的XOR运算符实际上是表达式(Boolean(state1) !== Boolean(state2))。对于布尔值,“ xy”,true 12、4 和均为真实值,应转换为true。所以("xy" XOR true)应该是false,但是("xy" !== true)是不是true,正如你指出。因此,!==仅当应用之前将其参数转换为布尔值时!=(两者)都等同于“逻辑XOR” 。
Doin

2

在上面的xor函数中,由于逻辑xor与逻辑xor并不完全相同,因此将得出类似的结果,这意味着在考虑数据类型匹配的情况下,它将得出“相等值为false”“不同值为true”

此xor函数将用作实际的xor或逻辑运算符,这意味着根据传递的值是true还是falsy,它将得出 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

在打字稿中(“ +”更改为数值):

value : number = (+false ^ +true)

所以:

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

在正常的javascript中,@ Sheraff与booleans兼容!!(false ^ true)。在打字稿中,+必须使其有效!!(+false ^ +true)
pfg

1

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])}`)
}


0

之所以没有逻辑XOR(^^),是因为与&&和||不同 它没有任何懒惰逻辑的优势。那就是必须同时评估左右两个表达式的状态。


0

这是一个使用2个以上变量并提供计数作为奖励的替代解决方案。

这是一个更通用的解决方案,可以为任何真值/假值模拟逻辑XOR,就像在标准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!` );

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

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

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

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

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

0

嘿,我找到了这个解决方案,可以在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
}

-2

试试这个简短易懂的

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

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

这适用于任何数据类型


3
这不适用于所有数据类型。与逻辑类型强制运算符一样,我希望“ foo” xor“ bar”为假,因为两者都是真实的。目前您的函数不是这种情况。通常,这样做true == someboolean不是必需的,因此,实际上,您要做的就是将严格的不等于包装到函数中。
Gijs 2013年

嗨,GiJs,我同意您的说法,“ foo”和“ bar”是真实值。但是我在编写函数时要牢记,它会产生与xor相似的输出(不相等的值会导致true,相等的值会导致false),而不仅仅是真/假值。在这种情况下,我发现了更多用法。但是我在下面的另一个答案中写了真正的逻辑异或。
2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.