当按位运算符做同样的事情时,为啥要使用逻辑运算符?

Posted

技术标签:

【中文标题】当按位运算符做同样的事情时,为啥要使用逻辑运算符?【英文标题】:Why use logical operators when bitwise operators do the same?当按位运算符做同样的事情时,为什么要使用逻辑运算符? 【发布时间】:2013-01-30 00:46:13 【问题描述】:

考虑这种情况:

(true & true & false & false & true) == true //returns: false

如您所见,按位与行为与逻辑与完全一样:

(true && true && false && false && true) == true //returns: false

我想知道为什么当按位运算与逻辑运算相同时,我应该使用逻辑运算。

注意:请不要因为性能问题而回答,因为它在 Mozilla Firefox 中要快得多,请参阅这个 jsPerf:http://jsperf.com/bitwise-logical-and

【问题讨论】:

在第二个例子中,我认为如果第一个值为 false,则不会评估其余值,因为该语句不能为 true。 您的性能测试有缺陷。您仅使用 truefalse 值进行测试。当你用真正的函数替换时,性能问题就会出现。 如果有记忆,& 会继续评估所有选项,而&& 会在第一个false 处停止,因此不会评估其他条件。 如果您将& 替换为+*,您的第一个sn-p 仍然有效。这并不意味着 +* 总是 与布尔值 && 一样。 对一位的按位运算有点太多了;) 【参考方案1】:

使用逻辑运算符的短路评估最常见的用途不是性能,而是避免错误。看到这个:

if (a && a.length)

你不能在这里简单地使用&

请注意,当您不处理布尔值时,无法使用& 而不是&&。例如& 上的201 二进制)和410 二进制)是0

还要注意,除了在if 测试中,&&(就像||)也被使用,因为it returns one of the operands:

"a" & "b" => 0
"a" && "b" => "b"

更一般地说,通常可以使用& 代替&&。就像在您的 javascript 代码中省略大多数 ; 一样。但它会迫使你思考多余的东西(或者会不时给你带来奇怪的错误)。

【讨论】:

Lazy evaluation 通常比short-circuit evaluation 具有更广泛/不同的含义。 @phant0m 短路在这里更精确,是的。已更新。【参考方案2】:

按位运算的行为是否相同?

不,不是。位运算符适用于整数,而逻辑运算符具有截然不同的语义。只有当使用纯布尔值时,结果可能是相似的。

Bitwise operators:计算两个操作数,转换为 32 位整数,对它们进行运算,然后返回数字。 Logical operators:评估第一个操作数,如果它是真/假,则评估并返回第二个操作数,否则返回第一个结果。这称为Short-circuit evaluation

您已经可以看到结果类型的这种差异:

(true & true & false & false & true) === 0
(true && true && false && false && true) === false

【讨论】:

【参考方案3】:

不,他们不这样做。区别在于:

    是否转换操作数类型 是否计算两个操作数 返回值
// sample functions 
function a()  console.log("a()"); return false; 
function b()  console.log("b()"); return true; 

&&(逻辑与)

    检查操作数的真实性 使用短路且不能计算第二个操作数 返回最后计算的操作数,不进行类型转换
a() && b();
// LOG: "a()"
// RET: false

&(按位与)

    临时将操作数转换为其 32 位整数表示(如有必要) 计算两个操作数 返回一个数字
a() & b();
// LOG: "a()"
// LOG: "b()"
// RET: 0

【讨论】:

您的意思可能是“按位与”而不是布尔值。【参考方案4】:

因为使用&&& 传达不同的意图。

第一个说你正在测试truthiness

第二个意思是你变了一些魔法。在实际代码中,您将看到variable1 & variable2很明显,您实际上是打算测试真实性(不是真实性)。代码的读者可能会感到困惑,因为不清楚为什么使用&

此外,正如许多其他帖子所指出的那样,考虑到布尔值和函数调用以外的其他值时,语义完全不同。

【讨论】:

你是对的 - 他们采用了“真实和虚假”(我个人的,无关紧要的懊恼;-)),也许你应该链接到一个解释(例如11heavens.com/falsy-and-truthy-in-javascript)。我将删除我原来的 cmets。 @MadKeithV 好主意,完成。那么,我也会删除我之前的 cmets。【参考方案5】:

几乎所有内容都已经说了,但为了完整起见,我想看看性能方面(你说的无关紧要,但很有可能):

JavaScript 有很多难以记住的关于如何计算表达式的规则。当涉及到更复杂的比较时,这包括很多类型转换(隐式类型强制)。数组和对象需要通过调用它们的toString() 方法进行转换,然后转换为数字。这会导致巨大的性能损失。

逻辑运算符&& 短路。这意味着一旦遇到falsy 值,评估就会停止并返回false。位运算符将始终计算整个语句。

当涉及非常昂贵的操作(转换数组和对象)时,请考虑以下(是的,非常极端的)短路示例:(性能根据 Chromium 90 中的https://jsbench.me)

// logical operator
( false &&  && [] ) == true
//  /\ short circuits here
// performance: 805M ops/sec  

// bitwise operator
( false  &   & [] ) == true // evaluates the entire statement
// performance: 3.7M ops/sec

您可以看到性能相差 100 倍!

【讨论】:

+1 不错,但基准测试并没有说性能很重要。在这种情况下,性能主要是红鲱鱼,因为语义完全不同。 语义主题已经被其他答案所覆盖,我只是想指出类型强制导致的性能问题。 您的回答没有说​​明哪种方式更快,也没有说明您的陈述适用于哪些运营商。 “数组和对象需要通过调用其 toString() 方法进行转换,然后转换为数字”用于逻辑或按位运算符?这个答案对读者只知道你在暗示什么做出了奇怪的假设,因此是不完整的。链接也坏了。 @KyleDelaney 我认为他的意思是两者都必须转换为字符串,然后转换为数字。如果其中一个没有受到影响,那么举一个短路的例子是没有意义的,因为你不知道哪个更快。我很确定他的意思是在这种情况下逻辑更快。 @KyleDelaney 即使你拉了一个不错的死灵(这个帖子已经有 8 年历史了 ;-)),为了清楚起见,我编辑了我的答案。我希望现在我想说的更清楚了?【参考方案6】:
    布尔值允许短路,这可以是性能提升或安全检查。 条件中使用的非布尔值。例如,if ( 1 & 2 ) 将返回 false,而 if ( 1 && 2 ) 将返回 true。

【讨论】:

我认为你不明白按位...试试(2&3)?"true":"false" @Christoph 打扰一下? (2&3) 将是真的,因为它是 0010 & 0011,即 0010。另一方面,(1&2)0001 & 0010,即 0000。我的观点是,如果您使用按位 &,使用非布尔值可能会得到意想不到的结果。 好的,我撤销了我的声明,但是Non-boolean values used in the conditional if will return false 这句话暗示这适用于所有情况,但事实并非如此。也许您想改写它,以便更清楚您的意思。 @Christoph 我认为您错过了“有条件”之后的时间段,但要点是。 :)【参考方案7】:

您不能短路按位运算符。此外,位运算符可以做更多的事情,而不仅仅是计算布尔表达式。

【讨论】:

【参考方案8】:

有一个巨大的区别:逻辑运算是短路的。这意味着 (true && true && false ) 是要执行的最后一件事。这允许强大的构造,例如使用var myFunc = mozilla.func || opera.sameFunc || webkit.evenOneMoreVariationOfTheSameConcept;的抽象工厂模型

按位运算的所有子表达式都必须完全求值——顺便说一句。无论如何,人们很少需要计算常量位或逻辑表达式。

【讨论】:

【参考方案9】:

第一个条件必须先转换然后求和。但是第二个会检查逻辑和返回值。

所以第一个会比第二个慢。

运行此测试:http://jsperf.com/bitwise-logical

在 Chrome 和 IE 上 Bitwise 较慢 但在 FireFox 上逻辑较慢

【讨论】:

对于布尔组合,第一个会更慢是不正确的。 && 添加分支,速度很慢。【参考方案10】:

按位运算符(& 和 |)将两个操作数转换为 32 位“整数”并返回位运算结果。如果操作数不是数字,则转换为 0。

逻辑运算符(&& 和 ||)根本不是逻辑运算符,而是操作数之一或 0 的选择器。

逻辑 && 如果两者都存在则返回第一个操作数,否则返回 0 逻辑 ||返回第一个现有操作数,否则返回 0 如果不存在则操作数存在:未定义、null、false 或 0

【讨论】:

【参考方案11】:
var bit1 = (((true & true) & (false & false)) & true), // return 0;
    bit2 = (((true && true) && (false && false)) && true); // return flase

alert(bit1 + ' is not ' + bit2);

【讨论】:

对不起,我没有找到你,正如@Christoph 之前提到的,0 等于 false

以上是关于当按位运算符做同样的事情时,为啥要使用逻辑运算符?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个逻辑/按位运算返回 1?

Dan Bernstein 的 Djb2 哈希函数:当我们只能乘以 33 时,为啥还要使用按位运算符?

逻辑与或非的使用方法

缩短按位方程

C语言里的按位异或运算符

为啥 tslint 中不允许按位运算符?