为什么函数有时返回0,有时返回false?

4
我写了下面的JavaScript函数,目的是在只有一个参数为真值时返回true:
function onlyOne( a, b, c) {
    return (a && !b && !c) ||
        (b && !a && !c) ||
        (c && !a && !b);
}

它的表现符合预期,只有在一些特定情况下会返回0

EXPECT true:
true = onlyOne( 1, 0, 0)
true = onlyOne( 0, 1, 0)
true = onlyOne( 0, 0, 1)

EXPECT false:
0 = onlyOne( 0, 0, 0)
false = onlyOne( 0, 1, 1)
false = onlyOne( 1, 0, 1)
0 = onlyOne( 1, 1, 0)
false = onlyOne( 1, 1, 1)

为什么在上述两种情况下它返回0而不是false? 我看到这些是唯一的两种负面情况,其中c为0,但我不知道这有什么区别。显然,在此处我没有理解JavaScript逻辑运算符和/或类型转换方面的某些内容。
以下是生成上述输出的完整代码。如果有所不同,我正在使用node.js 4.3.0从Windows命令行运行此代码:

    function testOnlyOne( a, b, c) {
        result = onlyOne(a, b, c);
        console.log("%j = onlyOne( %j, %j, %j)", result, a, b, c);
    }
    
    function onlyOne( a, b, c) {
        return (a && !b && !c) ||
            (b && !a && !c) ||
            (c && !a && !b);
    }
    
    console.log("\nEXPECT true:");
    testOnlyOne( 1, 0, 0);
    testOnlyOne( 0, 1, 0);
    testOnlyOne( 0, 0, 1);
    
    console.log("\nEXPECT false:");
    testOnlyOne( 0, 0, 0);
    testOnlyOne( 0, 1, 1);
    testOnlyOne( 1, 0, 1);
    testOnlyOne( 1, 1, 0);
    testOnlyOne( 1, 1, 1);


6
JavaScript的&&||运算符不一定返回布尔值。 - Pointy
2
如果第一个参数为0,则不需要执行以下可能将其转换为false的&&,因此它返回0。 如果第一个参数是1作为||,则不需要进行以下检查。 这就是所谓的短路逻辑。 - Taplar
3
将结果强制转换为布尔类型的常见方法是双重否定 (!!),例如 return !!((a && !b && !c) || (b && !a && !c) || (c && !a && !b)),这将始终产生一个布尔类型的结果。 - Will
http://jsfiddle.net/jmx543ae/ 作为一种替代方法,可以将其作为注释,因为这个问题确实不是关于重构的。 - Taplar
2个回答

1
因为JavaScript检查假值和真值的方式。例如,false0''undefinednull等值被视为假值(对于任何这些值,Boolean()的返回值都是false),而其他值如true1'hi'[]则被视为真值(对于任何这些值,Boolean()的返回值都是true)。
因此,执行 0 && 'a' 这样的指令将始终返回 0,因为 0 是假值,并且 && 运算符在任何值为 false 之后不会继续前进,因为对于 && 要返回 true,应用它的所有值都必须是真值。另一方面,执行 true && 'hello' && null 这样的指令将始终返回 null,因为直到 null 的所有第一个值都是真值,所以实际语句解析为 null

0

这篇博客文章可能值得一读,以了解为什么 JavaScript 会以这种方式处理事情。

&& 或 || 运算符产生的值不一定是布尔类型。产生的值将始终是两个操作数表达式之一的值。

&& 和 || 都会产生 (恰好) 一个操作数的值:

  • 如果 A 可以强制转换为 false,则 A && B 返回 A 的值;否则,返回 B 的值。
  • 如果 A 可以强制转换为 true,则 A || B 返回 A 的值;否则,返回 B 的值。

如果您想要结果作为布尔值,可以使用“非非”(not-not),像这样:!!expression


谢谢!这篇博客文章非常棒。我一直以为 && 和 || 的工作方式与 C 或 Java 中的相同... - Chad
这种行为更类似于Python,如果说有的话。在我看来,JS与Java或C几乎没有什么共同之处。值得注意的是,也许可以检查一下不同类型在表达式中的工作方式,例如if(x) if(!x) if(x==null) - geekley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接