【发布时间】:2011-05-31 05:42:40
【问题描述】:
为什么 JavaScript 中没有逻辑异或?
【问题讨论】:
标签: javascript xor logical-operators
为什么 JavaScript 中没有逻辑异或?
【问题讨论】:
标签: javascript xor logical-operators
将值转换为布尔形式,然后取bitwise XOR:
Boolean(a) ^ Boolean(b) // === 0 | 1
请注意,此表达式的结果是数字,不是布尔值。
Bitwise XOR 也适用于非布尔值,但请记住这是一个 bitwise 运算符,而不是逻辑运算符。使用非布尔值可能不会像您最初期望的那样:
(5 ^ 3) === 6 // true
【讨论】:
布尔值的一个衬线:
if (x ? !y : y) { do something cool }
【讨论】:
为了后代,并且因为我发现这是一个很好的练习,您可以很容易地利用 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))
【讨论】:
嘿,我找到了这个解决方案,可以在 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
}
【讨论】:
! 已经将操作数转换为布尔值。这意味着所有+ 所做的只是将true 或false 转换为1 或0,在这种情况下两者的结果相同。另外值得注意的是!!a ^ !!b 也等同于!a ^ !b。
这是一个替代解决方案,它使用 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.
【讨论】:
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])}`)
}
【讨论】:
function xor(cond1, cond2){ return !!cond1 + !!cond2 === 1 }
转换为布尔值,然后执行 xor like -
!!a ^ !!b
【讨论】:
!!a ^ !!b 等价于!a ^ !b。可以争论哪个更容易阅读。
在 Typescript 中(+ 变为数值):
value : number = (+false ^ +true)
所以:
value : boolean = (+false ^ +true) == 1
【讨论】:
!!(false ^ true) 可以很好地处理布尔值。在打字稿中,需要 + 才能使其有效!!(+false ^ +true)。
Javascript 中没有真正的逻辑布尔运算符(尽管! 非常接近)。逻辑运算符只会将true 或false 作为操作数,并且只会返回true 或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) { 这样的条件。非常混乱。
【讨论】:
Javascript 有一个按位异或运算符:^
var nb = 5^9 // = 12
您可以将它与布尔值一起使用,它会将结果作为 0 或 1(您可以将其转换回布尔值,例如 result = !!(op1 ^ op2))。但正如约翰所说,相当于result = (op1 != op2),更清晰。
【讨论】:
true^true 为 0,false^true 为 1。
|| 和 && 可以用作非布尔值的逻辑运算符(例如,5 || 7 返回真值,"bob" && null 返回假值)但 ^ 不能。例如,5 ^ 7 等于 2,这是真的。
(true ^ false) !== true,这使得需要实际布尔值的库很烦人
a ^= true 来切换布尔值,但它在某些机器(例如手机)上失败了。
myObj.collection[index].someImportantFlag = !myObj.collection[index].someImportantFlag,因此使用^= true 编写更方便。我再也不会被诱惑了:)
如何将结果 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);
【讨论】:
B = ((!state1)!==(!state2))
B =!!(!state1 ^ !state2); 另外,为什么有这么多括号? B = !state1 !== !state2; 或者你甚至可以放弃否定:B = state1 !== state2;
state1 !== state2,那么你不需要在那里进行任何转换,因为!== 是一个逻辑运算符,而不是按位运算符。 12 !== 4 是真的 'xy' !== true 也是真的。如果您使用!= 而不是!==,那么您将不得不进行强制转换。
!== 和!= 的结果总是布尔值......不确定你应该在那里做出什么区别,这绝对不是问题。问题是我们想要的XOR运算符实际上是表达式(Boolean(state1) !== Boolean(state2))。对于布尔值,“xy”、12、4 和true 都是真值,应转换为true。所以("xy" XOR true) 应该是false,但("xy" !== true) 是true,正如你所指出的。所以!== 或!= (两者)都等同于“逻辑异或”当且仅当您将它们的参数转换为布尔值在应用之前。
是的,只需执行以下操作。 假设您正在处理布尔值 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 |
------------------------------------------
享受吧。
【讨论】:
var xor1 = !(a === b); 与var xor1 = a !== b; 相同
!(2 === 3) 是true,但2 和3 是真实的 所以2 XOR 3 应该是false。
没有逻辑异或(^^)的原因是因为不像&&和||它没有提供任何惰性逻辑优势。也就是左右两边的表达式的状态都需要计算。
【讨论】:
两个布尔值的异或只是它们是否不同,因此:
Boolean(a) !== Boolean(b)
【讨论】:
^ 与布尔值一起使用时,TypeScript 会报错。
JavaScript 将其祖先追溯到 C,而 C 没有逻辑 XOR 运算符。主要是因为没用。按位异或非常有用,但在我多年的编程生涯中,我从来不需要逻辑异或。
如果你有两个布尔变量,你可以模拟 XOR:
if (a != b)
对于两个任意变量,您可以使用 ! 将它们强制转换为布尔值,然后使用相同的技巧:
if (!a != !b)
虽然这很模糊,但肯定值得评论。实际上,此时您甚至可以使用按位 XOR 运算符,尽管这对我来说太聪明了:
if (!a ^ !b)
【讨论】:
!= 唯一的问题是你不能和a ^= b 做同样的事情,因为a !== b 只是strict inequality 运算符。
a和b,异或确实是多余的。但是当人们已经有了布尔变量时,他们通常不需要布尔运算。你永远不会这样做const a = foo == bar; if (a == true) { console.log("foo=bar"); } 布尔运算的关键在于允许简单的内联测试,由编译器优化,没有定义无关变量的开销。
在上面的异或函数中,它会导致 SIMILAR 结果,因为逻辑异或不完全是逻辑异或,这意味着它将导致 "false for equal values" 和 " true for different values" 考虑到数据类型匹配。
这个异或函数将作为实际的异或或逻辑运算符工作,意味着它会根据传递的值是truthy或falsy得出真假强>。根据需要使用
function xor(x,y){return true==(!!x!==!!y);}
function xnor(x,y){return !xor(x,y);}
【讨论】:
(!!x) === (!!y) 相同。不同之处在于转换为布尔值。 '' === 0 为假,xnor('', 0) 为真。
试试这个简短易懂的
function xor(x,y){return true==(x!==y);}
function xnor(x,y){return !xor(x,y);}
这适用于任何数据类型
【讨论】:
true == someboolean 是不必要的,所以实际上,你所做的就是将严格的不等于包装到一个函数中。
有……有点:
if( foo ? !bar : bar ) {
...
}
或更容易阅读:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
为什么?不知道。
因为 javascript 开发人员认为这是不必要的,因为它可以由其他已实现的逻辑运算符表示。
您也可以只使用 nand,仅此而已,您可以从中打动所有其他可能的逻辑操作。
我个人认为,基于 c 的语法语言驱动它具有历史原因,据我所知,xor 不存在或至少非常罕见。
【讨论】:
【讨论】: