(NaN!= NaN)和(NaN!== NaN)有什么区别?


148

首先,我要提一提,我知道如何isNaN()Number.isNaN()工作。我正在阅读David Flanagan的《明确指南》,他举了一个示例说明如何检查该值是否为NaN

x !== x

这将在true且仅当x为时产生NaN

但是现在我有一个问题:他为什么要使用严格的比较?因为似乎

x != x

行为相同。是否可以安全使用的两个版本,或我很想念在JavaScript中的一些值(S),将返回truex !== xfalsex != x


10
弗拉纳根(Flanagan)可能更喜欢!==支票而不是!=支票。据我所知,where没有其他价值x != x。但也有JavaScript开发两个不同的群体:那些谁喜欢!=和那些喜欢谁!==,无论是速度,清晰度,表现力等
史蒂夫克洛斯特斯

30
当严格比较的行为方式相同时,为什么要使用宽松比较?
Ry-

3
@Raulucco:NaN不是唯一类型,而是一个数字。这是一个不等于其自身的唯一
TJ Crowder 2015年

8
标题似乎在误导人们。我建议将其更改为“ x!= x是否与x!== x有所不同?”
TJ Crowder 2015年

6
@femmestem:Giorgi说“在这种情况下”这是风格问题。他是对的。当操作数的类型同时,这不是样式,但是当它们相同时,这样式。另外:Flanagan正在===与NaN 进行比较,指出NaN不等于自身。他没有“错”,而是将其作为教学练习来进行,表明它不起作用。
TJ Crowder 2015年

Answers:


128

首先,让我指出这NaN是一个非常特殊的值:根据定义,它不等于自身。这来自使用JavaScript数字的IEEE-754标准。即使这些位完全匹配,“非数字”值也永远不会等于自身。(虽然它们不一定在IEEE-754中,但它允许多个不同的“非数字”值。)这就是为什么出现这种情况的原因。JavaScript中的所有其他值都等于自己,NaN只是很特殊。

...我缺少JavaScript中的某些值,该值将对x!== x返回true,对于x!= x返回false?

不你不是。!==和之间的唯一区别!=是,如果有必要使操作数的类型相同,后者将进行类型强制转换。在中x != x,操作数的类型相同,因此与完全相同x !== x

抽象平等操作的定义开始就可以清楚地看出:

  1. ReturnIfAbrupt(x)。
  2. ReturnIfAbrupt(y)。
  3. 如果Type(x)与Type(y)相同,则

    返回执行严格相等比较x === y的结果。

  4. ...

前两个步骤是基本的管道。因此,实际上,第一步==是查看类型是否相同,如果相同,则===改为进行更改。!=!==只是否定的那个版本。

因此,如果弗拉纳根(Flanagan)是正确的,那只NaN会为真。因此x !== x,我们可以肯定,也只会NaN为真x != x

许多JavaScript程序员都默认使用===,并!==避免周围的类型强制宽松的运营商做一些缺陷,但没有什么读入弗拉纳根在这种情况下使用的严格与宽松的经营者。


我已经重读了4.9.1 - Equality and Inequality Operators一节,这似乎是答案。===比较的关键点是: If the two values have the same type, test them for strict equality as described above. If they are strictly equal, they are equal. If they are not strictly equal, they are not equal
Giorgi Nakeuri 2015年

@GiorgiNakeuri:我不确定您指的是什么4.9.1,也许是Flanagan的书?但这基本上就是上面规范中的报价所说的,是的。
TJ Crowder 2015年

2
我接受这一点,是因为它以形式化和精确的方式回答了我的问题。谢谢您的解释!
Giorgi Nakeuri 2015年

1
@Moshe:“实时绑定”是什么意思?(该术语未出现在规范中。)您是否要说类似GOTO 0的示例,其中的示例a实际上是一个函数,并且不会两次返回相同的值?这与OP要求的值不同,这!==是正确的。它只是一个返回不同值的函数。foo() !== foo()也不一定是正确的,因为foo在每次调用时可能返回不同的值。
TJ Crowder 2015年

1
@Moshe好吧,这是使属性和吸气剂混乱的超级讨厌的方式。但这确实与GOTO 0的示例几乎相同,只是有一个额外的间接层。
JAB

37

楠的目的,!=!==做同样的事情。

但是,许多程序员避免使用JavaScript ==!=使用JavaScript。例如,道格拉斯·克罗克福德(Douglas Crockford)将它们视为JavaScript语言的“ 不良部分 ”,因为它们的行为方式令人意想不到且令人困惑:

JavaScript有两组相等运算符:===!==,以及它们的邪恶双胞胎==and !=。优秀的产品以您期望的方式工作。

...我的建议是不要使用邪恶的双胞胎。相反,请始终使用===!==


2
问题不是关于NaN(尽管标题)。问题是“我是否缺少JavaScript中的某些值,对于x!== x,它将返回true;对于x!= x,将返回false?”
TJ Crowder 2015年

@TJCrowder确实有两个问题。第一个问题是“使用两个版本是否安全”,答案是两个版本等效。我喜欢您的“幕后”答案,该答案详细解释了所有内容。
jkdev

22

只是为了好玩,让我向您展示一个人工的示例,该示例x不是,NaN但操作员的行为无论如何都不同。首先定义:

Object.defineProperty(
  self,
  'x',
  { get: function() { return self.y = self.y ? 0 : '0'; } }
);

那我们有

x != x // false

x !== x // true

9
哈!:-)但这实际上foo() != foo()是foo返回1到2的地方。例如,不相同,只是比较不同的值。
TJ Crowder 2015年

2

我只想指出,NaN不是x !== x不使用全局对象而产生的唯一东西。有很多聪明的方法来触发此行为。这是使用吸气剂的一种:

var i = 0, obj = { get x() { return i++; }};
with(obj) // force dynamic context, this is evil. 
console.log(x === x); // false

正如其他答案所指出的那样,==执行类型强制转换,但与其他语言一样使用标准和标准-NaN表示计算失败,并且由于充分的原因不等于其本身。

出于某种原因,人们认为这是JS的问题,但是大多数双精度语言(即C,Java,C ++,C#,Python等)都表现出这种确切的行为,人们对此表示满意。


2
是的,这正是@TJCrowder在GOTO_0的答案评论中提到的,不是吗?
Giorgi Nakeuri 2015年

您能否阐明这些其他语言如何获得模棱两可的类型强制?
chicocvenancio 2015年

0

有时,图像比文字要好,请检查此(这是我将其设为答案而不是注释的原因,因为它具有更好的可见性)。

在那里,您可以看到严格相等比较(===)仅在类型和内容匹配时返回true,因此

var f = "-1" === -1; //false

虽然抽象相等性比较(==)通过转换类型然后严格比较它们仅检查内容*:

var t = "-1" == -1; //true

尽管目前尚不清楚,但是如果不咨询ECMA,JavaScript在比较时会考虑什么,这种方式将使代码评估为true。

 var howAmISupposedToKnowThat = [] == false; //true
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.