为什么1==1==1返回true,"1"=="1"=="1"返回true,而"a"=="a"=="a"返回false?

114
function a() { return (1 == 1 == 1); }
function b() { return ("1" == "1" == "1"); }
function c() { return ("a" == "a" == "a"); }

我在Chrome的控制台中测试了上述代码,但不知何故,a()返回true,b()返回true,c()返回false。

为什么会这样?


79
提示:X == Y == Z 被解释为 ((X == Y) == Z)。 - Blackhole
14
奇怪的是,true == "1"计算结果为true - Codor
11
@Cupcake:我认为,出现一个在数学上看起来正确但实际上在JS中是错误的相等性,才是最令人困惑的地方,而不是例如true == 1是正确的。换句话说,顿悟时并不是意识到类型的作用,而是意识到所有这些都是将某个东西与true进行比较。我确信这里有重复的内容,但在我看来,这并不是你提供的那些之一。 - Jon
显示剩余5条评论
6个回答

185
因为你正在将第一个等式的(布尔)结果与第三个值的(非布尔)结果进行比较。
在代码中,1 == 1 == 1 相当于 (1 == 1) == 1 相当于 true == 1
这意味着这三种方法可以更简单地编写为:
function a() { return (true == 1); }
function b() { return (true == "1"); }
function c() { return (true == "a"); }

这些比较根据这些规则进行(强调是我的):

如果两个操作数的类型不相同,则 JavaScript 将操作数转换后,再应用严格比较。如果任一操作数为数字或布尔值,则在可能的情况下将操作数转换为数字;否则,如果任一操作数为字符串,则将字符串操作数转换为数字。如果两个操作数都是对象,则 JavaScript 比较内部引用,当操作数引用相同的内存中的同一对象时,它们是相等的。

所以,在 c 中发生的是,"a" 被转换为数字(得到NaN),然后与转换为数字的 true(得到 1)进行严格比较

由于 1 === NaNfalse,所以第三个函数返回 false。很容易看出前两个函数为什么会返回 true


27
值得一提的是,使用严格相等运算符(===)可以避免针对字符串 "1" 发生此类意外行为。 - Konrad Gadzina
12
“Strict equals”会使得这三个函数都返回false - Jon
1
你说得对。我在这里看到了很多“true”,以至于我忘记了那个。^^ - Konrad Gadzina
@Jon:在C语言中会发生什么是,“a”被转换为数字(得到NaN),因为没有一个操作数是数字。我认为这种转换最终会导致“true”==“a”,而不是1==NaN。 - Flater
5
@Flater:不。我引用的这段话非常清楚地说明了发生了什么(“如果任一操作数是数字或布尔值”——左侧操作数布尔值)。很容易看出你的断言是错误的:“1 == 1 ==“ true””=>“false”。 - Jon
显示剩余2条评论

26

由于 1 == true

但是 "a" != true

因此基本上发生的情况是:

1 == 1"1" == "1""a" == "a" 都被评估为 true,然后与下一个值进行比较。

字符串 "1" 在与 true 比较之前被转换为数字 (1),因此也被视为等于 true

现在,“为什么?!”的问题可以通过以下事实来解释:Javascript 的根源可以追溯到 C 类语言。在这些语言中,除了 0 以外的任何数字都被认为是有效的 true 布尔值。 :-/


5
JavaScript 绝对 不是 源自 C 语系。它的源头可以追溯到 LISP 方言,如 Scheme,并受到 Self 的启发。虽然 JavaScript 使用了 C 的语法,但并未使用其语义。在我看来,这是关于 JavaScript 最为广泛且错误的误解之一。为了强调这一点,请查看道格拉斯·克罗克福德(Douglas Crockford)的文章 JavaScript: The World's Most Misunderstood Programming Language - Golo Roden
3
@GoloRoden:不要傻了。如果JavaScript没有C语言的语义,诸如if(x = 5)的许多经典C语言语义错误在JS中就不存在了...但实际上它们确实存在,就像在C语言中一样。当然,它肯定没有完全继承C语言的语义,但它的行为更像C语言而不是任何Lisp语言。 - Mason Wheeler
5
@MasonWheeler 在条件下的任务不是一个错误或缺陷。 - Miles Rout
3
试着告诉每个曾被咬过它的人,不过这可能有点困难。 - Mason Wheeler
2
@funkybro 成为专业人士并不意味着不会发生意外。我已经编写 C 语言程序超过十年,但最近发现自己在 C 语言的 switch 语句中忘记了 break; - glglgl
显示剩余3条评论

6

由于1和"1"都被转换为数字true,这在"a"的情况下并不成立。因此:

("1" == "1" == "1") 

评估为

(("1" == "1") == "1") 

其评估结果为
(true == "1")

同样地,
("1" == 1 == "1") 

事实上,任何非零数字在转换为布尔值时都为真,包括正数、负数和小数。而字符串 "a" 不会被视为真。


5
由于JavaScript是一种弱类型语言,所以它不具备足够的表达能力来谈论类型,并且实际上会将值隐式地强制转换为与其无语义关系的类型。因此,(1 == 1) == 1 的结果为true,因为(1 == 1)正确地评估为true,所以JavaScript将(true)转换为1。特别地,它将1转换为布尔值(或true转换为数字——我忘了,但结果基本相同)。
重点在于JavaScript在你不知情的情况下将一个值类型转换为另一个值类型。你的问题就显示了这是一个问题:('a' == 'a') == 'a' 的结果为false,因为('a' == 'a')为true,JavaScript最终比较(true) == 'a'。由于没有将布尔值转换为字母(或将字母转换为布尔值)的明智方式,该语句为false。当然,这破坏了等于(==)的引用透明度。

2

确实,(1 == 1) == 1是正确的。那么它将会是true == 1,但不是在a == a == a中。


1
布尔值被视为位,每个位代表真或假(1表示真,0表示假)
因此,1表示真,0表示假
而1 == 1 == 1将会像(1 == 1)== 1,true == 1,true 而'a' == 'a' == 'a'将会像('a' == 'a')== 'a',true == 'a',false 奖励:0 == 1 == 0,1 == 0 == 0和0 == 0 == 1返回true

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