简体   繁体   English

为什么没有逻辑异或?

[英]Why is there no logical XOR?

Why is there no logical XOR in JavaScript?为什么JavaScript没有逻辑XOR或?

JavaScript traces its ancestry back to C, and C does not have a logical XOR operator. JavaScript 将其祖先追溯到 C,而 C 没有逻辑 XOR 运算符。 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:实际上,此时您甚至可以使用按位 XOR 运算符,尽管这对我来说太聪明了:

if (!a ^ !b)

Javascript has a bitwise XOR operator: ^ Javascript 有一个按位异或运算符:^

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, eg result = !!(op1 ^ op2) ).您可以将它与布尔值一起使用,它会将结果作为 0 或 1(您可以将其转换回布尔值,例如result = !!(op1 ^ op2) )。 But as John said, it's equivalent to result = (op1 != op2) , which is clearer.但正如约翰所说,它相当于result = (op1 != op2) ,更清楚。

There are no real logical boolean operators in Javascript (although ! comes quite close). Javascript 中没有真正的逻辑布尔运算符(尽管!非常接近)。 A logical operator would only take true or false as operands and would only return true or false .逻辑运算符只会将truefalse作为操作数,并且只会返回truefalse

In Javascript && and ||在 Javascript &&||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 ||在 Javascript &&||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. a() && b()评估a()并返回结果(如果它是假的)。 Otherwise it evaluates b() and returns the result.否则它计算b()并返回结果。 Therefore the returned result is truthy if both results are truthy, and falsy otherwise.因此,如果两个结果都为真,则返回的结果为真,否则为假。

a() || b() a() || b() evaluates a() and returns the result if it's truthy. a() || b()评估a()并返回结果(如果为真)。 Otherwise it evaluates b() and returns the result.否则它计算b()并返回结果。 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.但是这个结果的真值也可以用来决定一个“真正的”逻辑运算符是否会返回 true 或 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.我认为这就是为什么在 Javascript 中没有“逻辑”异或,以避免混淆。


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?所以也许undefined或.. 一个空数组? But an empty array is still truthy.但是空数组仍然是真实的。

Taking the array approach you would end up with conditions like if ((a ^^ b).length !== 1) { .采用数组方法,您最终会遇到类似if ((a ^^ b).length !== 1) {的条件。 Very confusing.非常混乱。

The XOR of two booleans is simply whether they are different, therefore:两个布尔值的异或只是它们是否不同,因此:

Boolean(a) !== Boolean(b)

Convert values into Boolean form and then take bitwise XOR :将值转换为布尔形式,然后进行按位异或

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

Note that the result of this expression is a number and not a Boolean.请注意,此表达式的结果是一个数字不是布尔值。

Bitwise XOR also works with non-Boolean values, but remember that this is a bitwise operator, and not a logical one.按位异或也适用于非布尔值,但请记住这是一个按位运算符,而不是逻辑运算符。 Using non-bools may not go as you first expect:使用非布尔值可能不会像您最初预期的那样:

(5 ^ 3) === 6 // true

Covert to boolean and then perform xor like -隐蔽为布尔值,然后像执行 xor -

!!a ^ !!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.因为 javascript 开发人员认为这是不必要的,因为它可以由其他已经实现的逻辑运算符表示。

you could as well just have gon with nand and thats it, you can impress every other possible logical operation from that.您也可以只使用 nand 和仅此而已,您可以从中给所有其他可能的逻辑操作留下深刻印象。

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.我个人认为它有历史原因驱动基于 c 的语法语言,据我所知 xor 不存在或至少不常见。

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假设您正在处理布尔值 A 和 B,那么可以使用以下代码在 JavaScript 中计算 A XOR B 值

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.就个人而言,我更喜欢 xor1,因为我需要输入的字符更少。 I believe that xor1 is also faster too.我相信 xor1 也更快。 It's just performing two calculations.它只是执行两个计算。 xor2 is performing three calculations. xor2 正在执行三个计算。

Visual Explanation... Read the table bellow (where 0 stands for false and 1 stands for true) and compare the 3rd and 5th columns.视觉解释...阅读下表(其中 0 代表错误,1 代表正确)并比较第 3 列和第 5 列。

:(A === B): :(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.享受。

Check out:查看:

You can mimic it something like this:你可以像这样模仿它:

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

How about transforming the result int to a bool with double negation?如何将结果int转换为带有双重否定的bool 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);

For posterity's sake, and because I found this to be a good exercise, you can leverage truthiness with the XOR operator quite easily to coerce.为了后代的利益,并且因为我发现这是一个很好的练习,您可以很容易地利用 XOR 运算符的真实性来强制执行。 Like the chosen answer, it's probably a bit too clever.就像选择的答案一样,它可能有点太聪明了。

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...

And for fun, this should work in TypeScript, by forcing explicit any:为了好玩,这应该在 TypeScript 中工作,通过强制显式 any:

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

One liner for Boolean:布尔值的一种衬垫:

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

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 .这个 xor 函数将作为实际的 xor 或逻辑运算符工作,这意味着它会根据传递的值是truthy还是falsy来产生 true 或 false 。 Use according to your needs根据您的需要使用

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

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

The reason there is no logical XOR (^^) is because unlike && and ||没有逻辑 XOR (^^) 的原因是因为不像 && 和 || 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):在 Typescript 中(+ 变为数值):

value : number = (+false ^ +true)

So:所以:

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

cond1 xor cond2 is equivalent to cond1 + cond 2 == 1 : cond1 xor cond2等同于cond1 + cond 2 == 1

Here's the proof:这是证明:

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

Here's an alternate solution that works with 2+ variables and provides count as bonus.这是一个替代解决方案,适用于 2+ 个变量并提供计数作为奖励。

Here's a more general solution to simulate logical XOR for any truthy/falsey values, just as if you'd have the operator in standard IF statements:这是一个更通用的解决方案,可以为任何真值/假值模拟逻辑异或,就像您在标准 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!` );

The reason I like this, is because it also answers "How many of these variables are truthy?", so I usually pre-store that result.我喜欢这个的原因是因为它还回答了“这些变量中有多少是真实的?”,所以我通常会预先存储那个结果。

And for those who want strict boolean-TRUE xor check behaviour, just do:对于那些想要严格的 boolean-TRUE 异或检查行为的人,只需执行以下操作:

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

If you don't care about the count, or if you care about optimal performance: then just use the bitwise xor on values coerced to boolean, for the truthy/falsy solution:如果您不关心计数,或者您关心最佳性能:那么只需对强制为布尔值的值使用按位异或,以获得真/假解决方案:

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

Hey I found this solution, to make and XOR on JavaScript and TypeScript.嘿,我找到了这个解决方案,可以在 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
}

Most of the proposed methods here are hard to read and understand.这里提出的大多数方法都很难阅读和理解。 Instead of writing some cryptic and magical comparisons or trying to comment them, just define a reusable function that is self-explanatory:与其编写一些神秘而神奇的比较或试图评论它们,不如定义一个不言自明的可重用 function :

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

Or a more universal one:或者更通用的:

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

Then you can use it like this:然后你可以像这样使用它:

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

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这适用于任何数据类型

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM