为什么!!1=="1"等于true,而!!2=="2"等于false?

66

正如标题所述,为什么会发生以下情况:

> !!1=="1"

相等的

True

> !!2=="2"

相等:

False
同样地,为什么> "1"==true等于true,而> "2"==true等于false
我感到困惑。这是JS中的错误吗?还是其他原因?

3
@Michael:对于你来说,2 ==“2”等于false吗?对我来说它是正常工作的。http://jsfiddle.net/HGEcs/(翻译:这句话询问Michael是否认为2 ==“2”等于false,然后表明对于作者来说代码运行正确,并提供了一个链接以支持他们的论点。) - Ishan Jain
8
在 JavaScript 中比较变量时,您应该始终使用 ===,原因如下。 - tester
54
不,这不是一个错误。如果你不知道其含义,则不应将布尔值与字符串进行比较。 - Bergi
12
这句话的意思是:根据“bug”的定义,这不是一个bug,但它确实存在设计缺陷。 - Harry Johnston
2
@MichaelRader:不,我没有(请看看我之前关于为什么它不是重复的评论)。实际上,我用我的金徽章特权重新打开了它 :-) 链接到页面 - Bergi
显示剩余9条评论
5个回答

207
根据 运算符优先级 规则,逻辑运算符 ! 的优先级高于 ==。因此,在两种情况下,!! 都会首先被计算。 注意:各种对象的真值已在我这篇答案中解释过。

第一种情况

!!1 == "1"

!1将被评估为false,因为1被认为是Truthy。再次取反,我们得到true。所以表达式变成了:

!1会被评估为false,因为1被视为Truthy(真的值)。再次取反后,它就变成了true。因此,该表达式变成了:

true == "1"

现在,因为你使用了==运算符,所以强制规则生效,该运算符的计算方式遵循在ECMAScript 5.1规范中定义的抽象相等比较算法

  

6. 如果Type(x)Boolean类型,则返回比较的结果ToNumber(x) == y

因此,true将被转换为数字,根据ToNumber布尔值算法,其结果为1。现在表达式变成了:

1 == "1"

现在,

4. 如果 Type(x)NumberType(y)String, 返回比较的结果 x == ToNumber(y)

因此,根据ToNumber算法,“1”将被转换为数字,结果将为1。这就是为什么第一个案例显示“true”的原因。

第二种情况

同样的规则也适用于这里。

!!2 == "2"

成为

true == "2"

然后

1 == "2"

这会变成

1 == 2

这是因为第二种情况打印的是 false,意味着它不是true


7
难怪100 == true总是为假。这引起了一些困惑,比如;除了1这个正数之外,如何使得负数正数== true都是假的?...你的解释真的在这个问题上阐明了一些重要的观点,尤其是第四点。 - ErickBest
5
如果你想比较值,那么你可能想使用 === 运算符,它使用严格相等算法 - thefourtheye
4
可以,但在着手之前请先阅读文档以了解“===”的限制。 ;-) - thefourtheye
4
我喜欢别人给出代码逐步解析,因为不是所有人都知道背后发生了什么。谢谢! - Chris Cirefice
1
如果您想从中创建一个语句,可以选择一些布尔代数,因此如果您有 var1 = 2var2 = 2,则可以使用 if !!var1 and var2,因为您不是检查这些数字的整数值,而是想要它们的布尔值。 - Jacqlyn
显示剩余6条评论

13
简而言之,这是由于==运算符算法中的[ToNumber]转换引起的。
第一步是简化表达式。由于!!x=="x"被解析为(!!x)=="x"!!a_truthy_expression -> true,因此相等性的实际相关表达式为:
!!1=="2" -> true=="1" -> Boolean==String
!!2=="2" -> true=="2" -> Boolean==String

因此,查看11.9.3抽象相等比较算法的规则并按照应用程序进行操作,得到以下结果:

规则6 - 如果Type(x)为Boolean,则返回比较ToNumber(x)==y的结果。

这会导致Number==String或1=="1"和1=="2"。然后应用规则:

规则7 - 如果Type(x)是Number且Type(y)是String,则返回比较x==ToNumber(y)的结果。

这会导致Number==Number或1==1 和1==2,后者显然是错误的。

规则1 - 如果Type(x)与Type(y)相同,则[由c.iii.]如果x与y是相同的Number值,则返回true[否则返回false]。

(当应用互补规则时,同样的算法解释了String==Boolean的情况。)

1要查看应用[ToNumber]规则,请考虑:

+false -> 0
+true  -> 1
+"1"   -> 1
+"2"   -> 2

5

这是一个优先级操作符问题。

! 操作符是一个一元操作符。这意味着左侧必须是一个表达式或可求值的布尔值。请参见 Javascript MDN

!!1==1 is not necessary !!(1==1)
!!2==2 is not necessary !!(2==2)

如果等于运算符比非运算符的优先级更高,我认为这些表达式应该保持一致。但是,如果我们考虑相反的情况,首先评估否定:

!!1 == 1
!1 -> false
!!1 -> true
!!1 == 1 

而且有这两个

!!2==2
!2 -> false
!!2 -> true
(!!2) == 2 -> false

那是因为"!"运算符的优先级高于"=="运算符。
请见Mozilla 运算符优先级

1
!!1等于true,"1"也等于true("0"是false,其他字符串也是)。所以!!1 == "1"等同于true == true,当然返回true。 !!2也等于true。如我之前提到的,"2"不是"1",因此是false。因此,我们有true == false,当然返回false。
如果您想查看数字2是否等于字符串表示形式的"2",那么您只需要执行2 == "2",这会得到2 == 2,为true。区别在于我们没有将布尔值与布尔值进行比较。我们正在将数字与数字进行比较。
基本上,在数字前面放置!!会将其转换为布尔值,这迫使JavaScript将您的字符串强制转换为布尔值而不是数字。

这正是我所说的。 - Meredith
你说过:“正如我之前提到的,‘2’不等于‘1’。”他说过2 == 1吗?请尝试解释一下这个观点。 - ErickBest
我说过,“1”是唯一等于true的字符串。因此,“2”等于false,这就导致了表达式true == false,因此!!2 == "2"是错误的。 - Meredith
7
字符串没有被转换成布尔值,而是布尔值被转换成数字。另外,""0"是false"这句话很令人困惑(如果不是错误的话),因为"0"是真值:!!"0" === true"0" == false - Bergi
4
这句话的意思是 !!"" === false, !!anyOtherString === true,也就是空字符串为假值,其他所有字符串都为真值。你的第一句话直接与此相矛盾。 - erm410

-1

因为在进行相等性检查时,“1”可能被视为“true”,而不是身份,但“2”则不行。


考虑 !!2!!1 - 两者都会评估为 true(因此,1和2都是真值)。 - user2864740

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