【问题标题】:Why is there no logical xor in JavaScript?为什么 JavaScript 中没有逻辑异或?
【发布时间】:2011-05-31 05:42:40
【问题描述】:

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

【问题讨论】:

    标签: javascript xor logical-operators


    【解决方案1】:

    将值转换为布尔形式,然后取bitwise XOR

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

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

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

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

    【讨论】:

      【解决方案2】:

      布尔值的一个衬线:

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 喜欢这个答案:)
        【解决方案4】:

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

        【讨论】:

        • 虽然解决方案有效,但它绝对是所有带有所有这些神秘符号的答案中可读性最低的。我宁愿看到评论里写的语句变成代码。
        • 这个解决方案有点过于复杂,没有任何收获。一元加号只是多余和不必要的,因为单个 ! 已经将操作数转换为布尔值。这意味着所有+ 所做的只是将truefalse 转换为10,在这种情况下两者的结果相同。另外值得注意的是!!a ^ !!b 也等同于!a ^ !b
        【解决方案5】:

        这是一个替代解决方案,它使用 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.
        

        【讨论】:

          【解决方案6】:

          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 }
          • @ChrisPerry 我理解你的建议。但我的回答是关于 XOR 的概念,它处理布尔实体。通过真实的比较,你最终会混淆我认为不应该混淆的概念。这是个人选择,我更喜欢将我的答案范围限制为布尔值。
          • JavaScript 的全部意义难道不是真正的符号应该混合吗?
          【解决方案7】:

          转换为布尔值,然后执行 xor like -

          !!a ^ !!b
          

          【讨论】:

          • 请注意!!a ^ !!b 等价于!a ^ !b。可以争论哪个更容易阅读。
          【解决方案8】:

          在 Typescript 中(+ 变为数值):

          value : number = (+false ^ +true)
          

          所以:

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

          【讨论】:

          • @Sheraff 在普通的 javascript 中,!!(false ^ true) 可以很好地处理布尔值。在打字稿中,需要 + 才能使其有效!!(+false ^ +true)
          【解决方案9】:

          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
          

          但是这个结果的真值也可以用来决定一个“真正的”逻辑运算符是返回真还是假。

          这样就可以写出类似的东西

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

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

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


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

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

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

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

          【讨论】:

          • 任何语言中的 XOR/^^ 总是必须评估两个操作数,因为它总是依赖于两者。 AND/&& 也是如此,因为所有操作数都必须为真(在 JS 中为真)返回传递。例外是 OR/||因为它必须只评估操作数,直到它找到一个真实的值。如果 OR 列表中的第一个操作数为真,则不会计算其他操作数。
          • 不过,您确实提出了一个很好的观点,即 JS 中的 XOR 必须打破 AND 和 OR 的约定。它实际上必须返回一个正确的布尔值,而不是两个操作数之一。其他任何事情都可能导致混乱/复杂。
          • @Percy AND/&& 如果第一个操作数为假,则不计算第二个操作数。它只计算操作数,直到找到一个假值。
          • @DDS 感谢您纠正答案。我很困惑为什么我自己没有注意到它。也许这在一定程度上解释了珀西的困惑。
          • 我的编辑被拒绝了,之后@matts 按照我修复它的方式重新编辑了它,所以我错过了我的(微不足道的)2 分。 3 人拒绝了它,我对他们使用的标准感到困惑。谢谢马特。
          【解决方案10】:

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

          var nb = 5^9 // = 12
          

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

          【讨论】:

          • 您可以将其用作逻辑异或。 true^true 为 0,false^true 为 1。
          • @Pikrass 您可以将其用作逻辑运算符在布尔值 上,但不能在其他类型上使用。 ||&& 可以用作非布尔值的逻辑运算符(例如,5 || 7 返回真值,"bob" && null 返回假值)但 ^ 不能。例如,5 ^ 7 等于 2,这是真的。
          • @Pikrass 但遗憾的是,(true ^ false) !== true,这使得需要实际布尔值的库很烦人
          • @Pikrass 您永远不应该将它用作布尔值的逻辑运算符,因为实现取决于操作系统。我正在使用某种a ^= true 来切换布尔值,但它在某些机器(例如手机)上失败了。
          • @cronvel 当然,只是有时,您尝试缩短超长路径,例如myObj.collection[index].someImportantFlag = !myObj.collection[index].someImportantFlag,因此使用^= true 编写更方便。我再也不会被诱惑了:)
          【解决方案11】:

          如何将结果 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,正如你所指出的。所以!==!= (两者)都等同于“逻辑异或”当且仅当您将它们的参数转换为布尔值在应用之前
          【解决方案12】:

          是的,只需执行以下操作。 假设您正在处理布尔值 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; 相同
          • 此答案不适用于所有数据类型(如 Premchandra 的答案)。例如!(2 === 3)true,但23真实的 所以2 XOR 3 应该是false
          • 如果您更仔细地阅读我的信息,您会注意到我写了“假设您正在处理布尔值 A 和 B ...”。
          【解决方案13】:

          没有逻辑异或(^^)的原因是因为不像&&和||它没有提供任何惰性逻辑优势。也就是左右两边的表达式的状态都需要计算。

          【讨论】:

            【解决方案14】:

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

            Boolean(a) !== Boolean(b)
            

            【讨论】:

            • 我不得不使用这个解决方案,因为当您尝试将 ^ 与布尔值一起使用时,TypeScript 会报错。
            【解决方案15】:

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

            如果你有两个布尔变量,你可以模拟 XOR:

            if (a != b)
            

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

            if (!a != !b)
            

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

            if (!a ^ !b)
            

            【讨论】:

            • != 唯一的问题是你不能和a ^= b 做同样的事情,因为a !== b 只是strict inequality 运算符。
            • 只要你已经有两个布尔变量ab,异或确实是多余的。但是当人们已经有了布尔变量时,他们通常不需要布尔运算。你永远不会这样做const a = foo == bar; if (a == true) { console.log("foo=bar"); } 布尔运算的关键在于允许简单的内联测试,由编译器优化,没有定义无关变量的开销。
            【解决方案16】:

            在上面的异或函数中,它会导致 SIMILAR 结果,因为逻辑异或不完全是逻辑异或,这意味着它将导致 "false for equal values"" true for different values" 考虑到数据类型匹配。

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

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

            【讨论】:

            • "xnor" 与 "===" 相同。
            • @daniel1426 不完全是。与(!!x) === (!!y) 相同。不同之处在于转换为布尔值。 '' === 0 为假,xnor('', 0) 为真。
            【解决方案17】:

            试试这个简短易懂的

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

            这适用于任何数据类型

            【讨论】:

            • 这不适用于所有数据类型。与逻辑类型强制运算符一样,我希望 "foo" xor "bar" 为假,因为两者都是真实的。您的功能目前并非如此。一般来说,true == someboolean 是不必要的,所以实际上,你所做的就是将严格的不等于包装到一个函数中。
            • 嗨 GiJs,我同意你的论点,“foo”和“bar”是真实的值。但是我写这个函数时要记住,它会产生与 xor 相似的输出(不相等的值结果为真,相等的值结果为假),而不仅仅是真值/假值。在这种情况下,我发现了更多的用法。但我在下面的另一个答案中写了真正的逻辑异或。
            【解决方案18】:

            有……有点:

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

            或更容易阅读:

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

            为什么?不知道。

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

            您也可以只使用 nand,仅此而已,您可以从中打动所有其他可能的逻辑操作。

            我个人认为,基于 c 的语法语言驱动它具有历史原因,据我所知,xor 不存在或至少非常罕见。

            【讨论】:

            • 是的,javascript 有三元运算。
            • C 和 Java 都使用 ^(插入符号)字符进行异或。
            【解决方案19】:

            退房:

            你可以像这样模仿它:

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

            【讨论】:

            • 嘿,如果他们在 JavaScript 中添加了一个逻辑 XOR 运算符,它会使代码示例看起来更简洁。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-09-04
            • 2022-01-13
            • 2014-12-10
            • 1970-01-01
            相关资源
            最近更新 更多