为什么 (0 < 5 < 3) 返回 true?

359

我在jsfiddle.net上玩耍,想知道为什么这会返回true?

if(0 < 5 < 3) {
    alert("True");
}

那么这个也是一样的:

if(0 < 5 < 2) {
    alert("True");
}

但这个不行:

if(0 < 5 < 1) {
    alert("True");
}

这种怪癖有用处吗?


14
你知道 http://wtfjs.com/ 吗? - Harmen
1
哈!不,我以前从未见过那个。 - punkrockbuddyholly
啊,隐式类型转换的乐趣。 - Jörg W Mittag
4
有用吗?可能适用于混淆。 :-) - Icode4food
为什么?此外,任何东西都是有用的,只要你能找到需要它的情况。确实,这个工具比许多其他工具更少被需要,但有时候,虽然可能很少,但它可能正好是完成工作的工具。 - temporary_user_name
15个回答

453

计算顺序导致在javascript中将(0 < 5 < 3)解释为((0 < 5) < 3),产生(true < 3),而true被计算为1,导致它返回true。

这也是为什么(0 < 5 < 1)返回false,(0 < 5)返回true,它被解释为1,导致(1 < 1)


161
因为JavaScript和Python不一样。 :-) - rsenna
1
你在我编辑问题并添加 if(0 < 5 < 1) == false 的时候回答了。现在一切都清楚了,谢谢 :) - punkrockbuddyholly
28
没问题,Python 是我所知道的唯一将这种语法解读为 ((0 < 5) && (5 < 3)) 的语言,可能还有其他语言也是如此,但我不知道。 - Alan Geleynse
18
Mathematica是另一个例子。 - Joren
而且也不是 Ruby... :P - Vitor Tyburski
2
在我看来,JavaScript 在尝试将布尔值与数字进行比较时应该引发 TypeError 异常,因为这没有意义。 - Michał Perłakowski

64

我猜是因为0 < 5是正确的,而true < 3被转换为1 < 3,其结果也是正确的。


7
这里没有使用类型转换符(cast)。类型转换符是程序员用来显式检查类型的运算符。这是从布尔型到整型的隐式转换。 - erickson
4
@erickson,真的吗……我们需要在这里纠结于语义吗? - CaffGeek
2
不用担心Erickson,我也误用了“语义”这个词。 :) - Mateen Ulhaq
10
无论如何,正确的术语是“强制”。而且,是的,Erickson 在绝对确定性方面有些错误。无论如何,强制都是一种类型转换,即使通常(但这只是约定俗成),使用“转换”一词来表示显式类型转换。类型转换 == 类型强制转换。 - Jack
1
一路上都是诡辩家... 不过回复还是“简洁而美好”的 ;) - Arman

22

可能是因为假设true1

0 < 5 < 3  -->  true < 3 -->  1 < 3  --> true

18

因为 true < 3,因为 true == 1


11

关于你的问题,这种怪异行为是否有用:我想可能会有一些情况下它是有用的(如果紧凑的代码是你追求的目标的话),但过分依赖它很可能会严重降低你的代码可读性。

这就像在更大的表达式中使用后置/前置递增/递减一样。你能一眼判断出这段代码的结果吗?

int x = 5;
int result = ++x + x++ + --x;

注意:使用这段代码,有时根据语言和编译器的不同,您甚至可以获得不同的结果。

为了使自己和下一个人更容易阅读代码,最好清晰地写出您实际想要发生的事情,而不是依赖于布尔值的隐式转换等副作用,从而使生活变得轻松愉快。


出于好奇,result 是18吗? - punkrockbuddyholly
6
@MrMisterMan: 我不确定Javascript,但在Java和C#中,评估保证从左到右进行,结果确实是18。在某些语言中,例如C和C ++,不能保证从左到右进行评估,根据编译器添加的优化,可能会得到不同的结果。 - Zach Johnson

9
第二部分问题的答案是,“这种怪癖有用吗?”也许是否定的,正如前面的回答所指出的那样,如果它确实是语言(Javascript)中将true转换为1的怪癖,但程序员通常不认为1和true(以及0和false)是相同的东西。
然而,如果您心中认为1是true,0是false,那么就会导致各种漂亮的布尔技巧,这些技巧非常有用、强大和直接。例如,您可以直接使用A>100的结果来增加计数器,这将在A大于100时增加计数器。这种技术可能被视为Java中的怪癖或技巧,在数组或函数语言中可能是惯用的。
在数组语言APL中的一个经典例子是计算数组中大于100的项数:
+/A>100

如果A是一个包含5个元素的数组,元素分别为107、22、256、110和3,则:

A>100

产生一个由5个布尔值组成的数组:
1 0 1 1 0
并对这个布尔结果进行求和:
+/1 0 1 1 0

产生最终答案的代码为:

3

这个问题是一个完美的例子,展示了这种技巧非常有用的地方,特别是当问题被概括为确定n个布尔值中至少有m个为真时。 检查至少有两个布尔值为真的方法

7
那很简单。
(0 < 5 < 3)

从左到右开始,因此它首先评估第一个0 < 5。它是真的吗?是的。由于TRUE=1,它评估1 < 3。由于1小于3,因此它是真的。

现在来看这个:

 (0 < 5 < 1)

0是否小于5?是的。所以把它变成TRUE,这也意味着1。现在有了这个事实,它被评估为(1 < 1)。1是否小于1?不是,因此它是假的。它必须相等。


4

我之前在 Obj-C 中遇到了这个问题,感到非常困惑。通过类似以下的方式,我得到了期望的结果:

if(0 < 5  && 5 < 3) {
alert("True");}

当然这是错误的,所以你不会看到 "true" 的提示框。 我很高兴读到这个,现在我明白了原因。

4

这是在判断0<5,由于1<3也为真,因此返回1表示真。

C#不允许您这样做:“运算符'<'不能应用于类型为'bool'和'int'的操作数”。


有时候我会在动态语言中想念C#的严谨性。 - Arman

4
除了Python之外,CoffeeScript也支持链式比较,因此3 < x < 10将在vanilla JS中转换为(3 < x && x < 10)

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