在JavaScript中,为什么"0"等于false,但在使用'if'测试时它本身不是false?

287
以下说明了在JavaScript中"0"被视为假(false):
>>> "0" == false
true

>>> false == "0"
true
所以为什么以下代码会输出 "ha"
>>> if ("0") console.log("ha")
ha

63
"0" 是一个字符串,由于它不是空的,所以被认为是真(true)。 - Digital Plane
10
"0" === false [...] false - user1385191
3
请查看Angus Croll的文章《JavaScript中的真相》。http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/ - timrwood
9
'0'==false 但是 '0' 不是假值(是的,JavaScript 可能很奇怪) - Linsey
8
@Linsey: "falsy"和"truthy"只是用来解释值如何转换为布尔值,当你使用==比较两个值时,它们永远不会被转换为布尔值,因此这个概念不适用。(这种转换规则更倾向于将值转换为数字。) - millimoose
显示剩余3条评论
15个回答

429

2
用另一种数值顺序会更有意义。https://gist.github.com/kirilloid/8165660 - kirilloid
4
从现在开始,如果有人说他从不使用严格比较运算符,我会拿出这些表格让他哭泣。但我仍然不确定我是否理解了“NaN”的概念。我的意思是,typeof NaN // number但是 NaN === NaN // false,嗯... - Justus Romijn
4
我朋友制作了http://f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - 与上面相同的图表,但更易于阅读。 - Lucy Bain
这真的很有用。当我看到“==”的表格时,我再次知道为什么我永远避免那种比较方式。 - Hinrich
5
这些表格有错误。对于[]{}[[]][0][1]的值,既无==操作符也无===操作符会得出真值。我是说[] == [][] === [] 也是假的。 - Herbertusz
显示剩余4条评论

296

原因是当你显式地执行"0" == false时,双方都被转换为数字,然后进行比较。

而当你执行 if ("0") console.log("ha") 时,测试的是字符串值。任何非空字符串都是 true,而空字符串则是 false

等于(==)

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

(摘自 Mozilla 开发者网络上的比较运算符)


44

这是技术规范的要求。

12.5 if语句 
.....
2. 如果 ToBoolean(GetValue(exprRef)) 为true, 则 a. 返回第一个语句的评估结果。 3. 否则, ....

ToBoolean在规范中的定义为:

ToBoolean是抽象操作,根据表11将其参数转换为布尔类型的值:

这个表格对字符串的说明如下:

enter image description here

如果参数是空字符串(长度为零),则结果为false;否则结果为true

现在,为什么"0" == false需要解释,你需要阅读相等运算符,它表明它从左侧和右侧都匹配为抽象操作GetValue(lref)的值。

这个相关部分的描述如下:

如果IsPropertyReference(V)为真,则
a. 如果HasPrimitiveBase(V)为假,则让get成为base的[[Get]]内部方法, 否则让get成为下面定义的特殊[[Get]]内部方法。
b. 使用base作为其this值调用get内部方法的结果,并将GetReferencedName(V)作为参数传递返回

换句话说,字符串有一个原始基础,它调用内部的get方法,最终看起来是false。

如果要使用GetValue操作评估表达式,请使用==,如果要使用ToBoolean进行评估,请使用===(也称为“严格”相等运算符)。


一个字符串具有原始基础,它调用内部的get方法,并最终看起来是false。这对所有字符串都适用吗? - aziz punjani
@Interstellar_Coder Section 8.12.3: [[Get]] (P) 描述了它的工作原理。只有在字符串为0的情况下才是正确的,因为它最终会调用一堆其他的内部调用,最终导致GetOwnProperty看到“whatever”是一个数据属性,然后返回该值。这就是为什么“0”为假,“blah”为真的原因。请查看Douglas Crockford在Yahoo开发者剧院中的一些视频,他比我更简单地描述了JavaScript中的“truthyness”。如果你理解了“truthy”和“falsy”的含义,你就能立刻理解Bobince的答案。 - Incognito
1
我在哪里能找到规范? - user985366

13

这里提到的是PHP中的字符串"0"是falsy(在布尔上下文中使用时为false)。而在JavaScript中,所有非空字符串都是truthy。

问题在于,对布尔值进行==比较时并不是在布尔上下文中进行的,而是将其转换为数字。对于字符串而言,它会被解析为十进制数字,因此你得到的是数字0而不是truthiness布尔值true

这是一种非常糟糕的语言设计,这也是我们尽量不使用不幸的==运算符的原因之一。应该使用===代替。


8
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.

8

你在0周围加上引号,这使它成为了一个字符串,被解释为true。

移除引号,它就可以正常工作。

if (0) console.log("ha") 

2
正确的翻译应该是,不是关于如何“使其工作”,而是更像是一个问题:“为什么它会表现出那种方式?” - nonopolarity
有趣的是,经过这么多年,正确的答案就在这里,但很少有人注意到。@JasonGennaro,感谢你没有忽视显而易见的事实。 - davidhartman00

2

== 等于运算符会将参数转换为数字后再进行比较。因此,字符串零“0”会被转换为数字类型,布尔值false会被转换为数字0。

"0" == false // true

同样适用于:

false == "0" //true

=== 严格相等运算符会保留原始数据类型,对参数进行比较。

"0" === false // false, 因为"0"是字符串而false是布尔值

同样适用于:

false === "0" // false

if("0") console.log("ha");

字符串“0”并不与任何参数进行比较,只有在与其他参数进行比较时才会被视为真值。这就像

if(true) console.log("ha");

但是

if (0) console.log("ha"); // 空的控制台行,因为0是假值


2

这就是为什么尽可能使用严格相等 === 或严格不等 !==

"100" == 100

true,因为它只检查值,而不是数据类型

"100" === 100

false,因为它检查值和数据类型


2

我不知道有人将规范移植到网站上...太棒了!我再也不需要PDF了。 - Incognito

2
这是因为JavaScript在布尔上下文中使用类型转换,而您的代码需要进行一些改进。
if ("0") 

在布尔环境中,它将被强制转换为true。

Javascript中还有其他真值,它们将在布尔环境中被强制转换为true,因此执行if块的是:

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)


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