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

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

首先我想提一下,我知道 isNaN()Number.isNaN() 是如何工作的。我正在阅读 David Flanagan 的 The Definite Guide,他举例说明了如何检查值是否为 NaN:

x !== x

这将导致 true 当且仅当 xNaN

但是现在我有一个疑问:他为什么要用严格比较呢?因为好像

x != x

行为相同。使用这两个版本是否安全,或者我在 JavaScript 中遗漏了一些值,这些值将 return true 用于 x !== xfalse 用于 x != x?

为了 NaN 的目的,!=!== 做同样的事情。

然而,许多程序员在JavaScript中避免使用==!=。例如,Douglas Crockford 认为它们属于 JavaScript 语言的“bad parts”,因为它们的行为方式出乎意料且令人困惑:

JavaScript has two sets of equality operators: === and !==, and their evil twins == and !=. The good ones work the way you would expect.

...My advice is to never use the evil twins. Instead, always use === and !==.

首先,让我指出 NaN 是一个非常特殊的值:根据定义,它不等于自身。这来自 JavaScript 数字所依据的 IEEE-754 标准。 "not a number" 值永远不会等于其自身,即使位完全匹配也是如此。 (它们不一定在 IEEE-754 中,它允许多个不同的 "not a number" 值。)这就是为什么会出现这个问题; JavaScript 中的所有其他值都等于它们自己,NaN 只是特殊值。

...am I missing some value in JavaScript that will return true for x !== x and false for x != x?

不,你不是。 !==!= 之间的唯一区别是后者将在必要时进行类型强制以使操作数的类型相同。在x != x中,操作数的类型相同,所以和x !== x.

完全一样

Abstract Equality Operation的定义开始就很清楚了:

  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is the same as Type(y), then

    Return the result of performing Strict Equality Comparison x === y.

  4. ...

前两步是基本管道。所以实际上,== 的第一步是查看类型是否相同,如果是,则执行 ===!=!== 只是它的否定版本。

因此,如果弗拉纳根是正确的,只有 NaN 会为 x !== x 提供真值,我们可以肯定只有 NaN 会为 [=14= 提供真值] ].

许多 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 的东西。有很多聪明的方法可以触发这种行为。这是一个使用吸气剂的方法:

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 等)都表现出这种确切的行为人们对此很满意。

有时候,图片胜于文字,请查看此 table(这就是我将其作为答案而不是评论的原因,因为它的可见度更高)。

您可以看到严格相等比较 (===) 只有 returns 如果类型和内容匹配才为真,所以

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

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

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

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

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