为什么没有逻辑异或?

发布于 2024-10-09 18:52:46 字数 44 浏览 0 评论 0原文

为什么 JavaScript 中没有逻辑XOR

Why is there no logical XOR in JavaScript?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

爱,才寂寞 2024-10-16 18:52:46

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

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

if (a != b)

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

if (!a != !b)

虽然这很晦涩,但肯定值得评论。事实上,此时您甚至可以使用按位异或运算符,尽管这对我来说太聪明了:

if (!a ^ !b)

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)
嘿嘿嘿 2024-10-16 18:52:46

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

var nb = 5^9 // = 12

您可以将它与布尔值一起使用,它将给出 0 或 1 的结果(您可以将其转换回布尔值,例如 result = !!(op1 ^ op2))。但正如John所说,它相当于result = (op1 != op2),这样更清晰。

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.

温柔戏命师 2024-10-16 18:52:46

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

Boolean(a) !== Boolean(b)

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

Boolean(a) !== Boolean(b)
蓝礼 2024-10-16 18:52:46

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

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

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

在 Javascript &&|| 中,采用惰性快捷方式,在某些情况下评估第二个操作数,从而忽略其副作用。这种行为不可能通过逻辑异或来重新创建。


a() && b() 计算 a() 并在结果为假时返回结果。
否则,它会计算 b() 并返回结果。因此,如果两个结果都为真,则返回的结果为真,否则为假。

a() || b() 计算 a() 并返回结果(如果为真)。
否则,它会计算 b() 并返回结果。因此,如果两个结果均为假,则返回的结果为假,否则为真。

所以总体思路是首先评估左操作数。仅在必要时才评估正确的操作数。最后一个值就是结果。这个结果可以是任何结果。对象、数字、字符串……等等!

这使得可以编写像

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

or 这样

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

的东西,但是这个结果的真值也可以用来决定“真正的”逻辑运算符是否返回 true 或 false。

这使得可以编写类似

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

or 的

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

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


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

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

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

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

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.

或十年 2024-10-16 18:52:46

将值转换为布尔形式,然后采用按位异或

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

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

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

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

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
假情假意假温柔 2024-10-16 18:52:46

转换为布尔值,然后执行异或 -

!!a ^ !!b

Covert to boolean and then perform xor like -

!!a ^ !!b
迷离° 2024-10-16 18:52:46

有......有点:

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

或更容易阅读:

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

为什么?不知道。

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

你也可以只使用 nand ,仅此而已,你可以从中印象深刻所有其他可能的逻辑操作。

我个人认为它有历史原因,是从基于 C 的语法语言驱动的,据我所知,异或不存在或至少极其不常见。

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.

゛清羽墨安 2024-10-16 18:52:46

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

var xor1 = a !== b;

一行也相当于以下内容

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

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

视觉解释...阅读下表(其中0代表false1代表true)并比较第三列和第五列。

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

享受吧。

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.

无悔心 2024-10-16 18:52:46

查看:

您可以像这样模仿它:

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

Check out:

You can mimic it something like this:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}
故事未完 2024-10-16 18:52:46

为了子孙后代,并且因为我发现这是一个很好的练习,您可以很容易地利用 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))

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

const xor = (a: any, b: any) => !!((!!a as any) ^ (!!b as any))
别念他 2024-10-16 18:52:46

布尔值的一个衬里:

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

One liner for Boolean:

if (x ? !y : y) { do something cool }
轮廓§ 2024-10-16 18:52:46

如何将结果 int 转换为带有双重否定的 bool ?不是那么漂亮,但非常紧凑。

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

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

魂ガ小子 2024-10-16 18:52:46

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

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

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

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

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);}
も星光 2024-10-16 18:52:46

没有逻辑 XOR (^^) 的原因是因为与 &&和||它没有提供任何惰性逻辑优势。也就是说,必须评估左右两个表达式的状态。

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.

萌逼全场 2024-10-16 18:52:46

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

value : number = (+false ^ +true)

所以:

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

In Typescript (The + changes to numeric value):

value : number = (+false ^ +true)

So:

value : boolean = (+false ^ +true) == 1
夜空下最亮的亮点 2024-10-16 18:52:46

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

cond1 xor cond2 is equivalent to 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])}`)
}

一身仙ぐ女味 2024-10-16 18:52:46

关于为什么不可用以及其他方法的大量讨论。我想关注的是如何使这个平易近人可扩展,以便它相当容易理解/维护,并且易于扩展为集合(数组)价值观;为此:

[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

利用数组的过滤器和长度成员并轻松适合内联。或者,可以在函数中重用,并加上示例使用:

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

Lots of discussion on why this is not available, and other methods. What I'd like to focus on is how to make this approachable and scalable so that it's reasonably easy to understand/maintain, and easy to extend for a collection (array) of values; to that end:

[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

Leverages the Array's filter and length members and easily fits inline. Or, can be made reusable in a function, plus sample use:

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
我早已燃尽 2024-10-16 18:52:46

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

这是一个更通用的解决方案,用于模拟任何 true/false 值的逻辑 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!` );

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

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

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

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

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

Here's an alternate solution that works with 2+ variables and provides count as bonus.

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:

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:

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.
美羊羊 2024-10-16 18:52:46

这里提出的大多数方法都很难阅读和理解。与其编写一些神秘而神奇的比较或尝试对其进行注释,只需定义一个不言自明的可重用函数:

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

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 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');
分分钟 2024-10-16 18:52:46

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

Hey I found this solution, to make and XOR on JavaScript and 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
}
深爱不及久伴 2024-10-16 18:52:46

尝试这个简短且易于理解的方法

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

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

这适用于任何数据类型

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文