(NaN!=NaN)和(NaN)之间有什么区别

What is the difference between (NaN != NaN) and (NaN !== NaN)?

本文关键字:NaN 什么 区别 之间      更新时间:2023-09-26

首先我想说的是,我知道isNaN()Number.isNaN()是如何工作的。我正在阅读David Flanagan的《确定性指南》,他给出了一个如何检查值是否为NaN:的例子

x !== x

这将导致true,当且仅当xNaN

但现在我有一个问题:他为什么要严格比较?因为

x != x

行为方式相同。使用这两个版本是否安全,或者我在JavaScript中缺少一些值,这些值将为x !== x返回true,为x != x返回false

首先,让我指出NaN是一个非常特殊的值:根据定义,它不等于自己。这源于JavaScript数字所采用的IEEE-754标准。"非数字"值永远不会等于它自己,即使比特完全匹配。(在IEEE-754中,它们不一定是这样,它允许多个不同的"非数字"值。)这就是为什么会出现这种情况;JavaScript中的所有其他值都等于它们自己,NaN只是特殊的。

我是否在JavaScript中丢失了一些值,该值将在x中返回true!==x为false!=x?

不,你不是。!==!=之间的唯一区别是,如果需要,后者将执行类型强制,以使操作数的类型相同。在x != x中,操作数的类型是相同的,因此它与x !== x完全相同。

这一点从抽象等式运算的定义开始就很清楚:

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

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

  4. 。。。

前两个步骤是基本的管道。因此,实际上,==的第一步是查看类型是否相同,如果是,则执行===。CCD_ 19和CCD_。

因此,如果Flanagan是正确的,只有NaNx !== x为真,那么我们可以确信,也只有NaNx != x为真。

许多JavaScript程序员默认使用===!==来避免松散运算符所做的类型强制方面的一些陷阱,但在这种情况下,Flanagan使用严格与松散运算符没有什么可解读的。

对于NaN,!=!==做相同的事情。

然而,许多程序员在JavaScript中避免使用==!=。例如,Douglas Crockford认为它们属于";坏零件";因为它们的行为方式出乎意料且令人困惑:

JavaScript有两组相等运算符:===!==,以及它们的邪恶双胞胎==!=。好的工作方式你会期望。

我的建议是永远不要使用邪恶的双胞胎。请始终使用===!==

为了好玩,让我向您展示一个人工示例,其中x不是NaN,但运算符的行为无论如何都不同。首先定义:

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

然后我们有

x != x // false

但是

x !== x // true

我只想指出,NaN并不是唯一一个在不使用全局对象的情况下生成x !== x的东西。有很多聪明的方法可以触发这种行为。下面是一个使用getters的例子:

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和其他语言)都表现出了这种确切的行为,人们对此很满意

有时,图像比文字更好,请查看此表(这就是我将其作为答案而不是注释的原因,因为它可以获得更好的可见性)。

在那里你可以看到,只有当类型和内容匹配时,严格的相等比较(==)才会返回true,所以

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

而抽象等式比较(==)只通过转换类型然后严格比较来检查内容*:

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

虽然在没有咨询ECMA的情况下,JavaScript在比较时会考虑什么还不清楚,下面的代码会评估为true。

 var howAmISupposedToKnowThat = [] == false; //true