JavaScript的起源可以追溯到C语言,而C语言并没有逻辑XOR运算符。主要是因为它没有什么用处。按位XOR非常有用,但在我多年的编程生涯中,我从未需要过逻辑XOR。
如果你有两个布尔变量,你可以用以下方式模拟XOR:
if (a != b)
有两个任意变量,你可以使用!
将它们强制转换为布尔值,然后使用相同的技巧:
if (!a != !b)
这虽然相当晦涩,但肯定值得注释。实际上,在这一点上,甚至可以使用按位异或运算符,但这对我来说过于聪明了:
if (!a ^ !b)
Javascript有一个按位异或运算符:^
var nb = 5^9 // = 12
你可以将布尔值用于这个操作,它会返回0或1(你可以将其转换回布尔值,例如result = !!(op1 ^ op2)
)。但正如John所说,这等同于result = (op1 != op2)
,更加清晰易懂。
true^true
等于 0,而 false^true
则等于 1。 - Pik'||
和 &&
可以用作非布尔类型的逻辑运算符(例如 5 || 7
返回一个truthy值,"bob" && null
返回一个falsey值),但 ^
不行。例如,5 ^ 7
等于2,这是一个truthy值。 - Mark Amery(true ^ false) !== true
,这让在需要实际布尔值的库中使用变得很麻烦。 - Izkataa ^= true
的方法来切换布尔值,但在某些机器上(如手机)会失败。 - MasadowmyObj.collection[index].someImportantFlag = !myObj.collection[index].someImportantFlag
,所以使用 ^= true
更方便。但我再也不会被诱惑了 :) - Masadow两个布尔值的XOR操作仅仅是判断它们是否不同,因此:
Boolean(a) !== Boolean(b)
^
操作符与布尔值一起使用时会报错。 - Nathan Arthur!
接近)。逻辑运算符只会将true
或false
作为操作数,并仅返回true
或false
。&&
和||
接受各种操作数并返回各种有趣的结果(无论您输入什么)。&&
和||
采用一种懒惰方法并且在某些情况下不评估第二个操作数,从而忽略了其副作用。这种行为无法使用逻辑异或来重新创建。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')) {
然而,“逻辑”异或运算符(^^
)始终必须评估两个操作数。这使它与其他“逻辑”运算符不同,后者仅在必要时评估第二个操作数。我认为这就是为什么 JavaScript 中没有“逻辑”异或的原因,以避免混淆。
那么如果两个操作数都为假值会发生什么?两个都可以返回。但只能返回一个。哪个?第一个吗?还是第二个?我的直觉告诉我返回第一个,但通常“逻辑”运算符从左到右进行求值并返回最后一个求值的值。或者可能返回包含两个值的数组?
如果一个操作数为真值,另一个操作数为假值,则异或应该返回真值。或者可能返回包含真值的数组,以使其与前面的情况兼容?
最后,如果两个操作数都为真值,您应该期望得到某些假值。但是没有假值结果。因此该操作不应返回任何内容。所以也许是 undefined
或..一个空数组?但是空数组仍然是真值。
采用数组方法,您将得到像 if ((a ^^ b).length !== 1) {
这样的条件,非常令人困惑。
将值转换为布尔形式,然后进行按位异或:
Boolean(a) ^ Boolean(b) // === 0 | 1
(5 ^ 3) === 6 // true
将其转换为布尔值,然后执行异或操作,如 -
!!a ^ !!b
!!a ^ !!b
等同于 !a ^ !b
。对于哪个更易读可能存在争议。 - tschwab有一种排序方式可能会更适合你:
if( foo ? !bar : bar ) {
...
}
更容易阅读:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
为什么?不知道。
因为JavaScript开发者认为它是不必要的,因为它可以通过其他已实现的逻辑运算符来表达。
你也可以选择使用NAND,然后就可以从中推断出所有可能的逻辑运算。
我个人认为,这有历史原因,源自于基于C语法的编程语言,在那里,xor不常见,或者至少极其不常见。
是的,只需要按照以下步骤进行操作。 假设您要处理的是布尔值 A 和 B,则可以使用以下 JavaScript 代码来计算 A 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 |
------------------------------------------
享受吧。
!(2 === 3)
是true
,但是2
和3
是“truthy”的,所以2 XOR 3
应该是false
。 - Mariano Desanzevar 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))
。 - DoinB =!!(!state1 ^ !state2);
另外,为什么要用这么多括号?B = !state1 !== !state2;
或者你甚至可以省略否定:B = state1 !== state2;
- Lajos Mészárosstate1 !== state2
,那么你在那里不需要进行任何转换,因为!==
是一个逻辑运算符,而不是位运算符。12 !== 4
是真的,'xy' !== true
也是真的。如果你使用!=
而不是!==
,那么你就必须进行转换。 - Lajos Mészáros!==
和!=
的结果始终是布尔值...不确定你所做的区分应该是什么,那绝对不是问题所在。问题在于我们想要的异或运算符实际上是表达式(Boolean(state1) !== Boolean(state2))
。对于布尔值,"xy"、12、4和true
都是真值,并且应该转换为true
。因此("xy" XOR true)
应该是false
,但是("xy" !== true)
却是true
,正如你所指出的那样。因此,!==
或!=
只有在应用之前将它们的参数转换为布尔值时才等同于"逻辑异或"。 - Doin
!=
的唯一问题是你不能像a ^= b
那样做,因为a !== b
只是 严格不等 运算符。 - mcpiromana
和b
,异或运算确实是多余的。但通常情况下,人们在拥有布尔变量时并不需要使用布尔运算。你永远不会这样做:const a = foo == bar; if (a == true) { console.log("foo=bar"); }
布尔运算的关键点在于允许进行简单的内联测试,由编译器进行优化,无需定义额外的变量。 - Bogdan Stăncescu