151

First of all I want to mention that I know how isNaN() and Number.isNaN() work. I am reading The Definite Guide by David Flanagan and he gives an example for how to check if the value is NaN:

x !== x

This will result in true if and only if x is NaN.

But now I have a question: why does he use strict comparison? Because it seems that

x != x

behaves the same way. Is it safe to use both versions, or I am missing some value(s) in JavaScript that will return true for x !== x and false for x != x?

Chris Sprague
  • 740
  • 1
  • 12
  • 22
Giorgi Nakeuri
  • 35,155
  • 8
  • 47
  • 75
  • In my opinion , strict comparison (===) is more accurate than the other. because it compares not only the value but also the data type of that object. – vistajess Dec 14 '15 at 07:48
  • 1
    @vistajess, ok, but the type of `NaN is number` and there is no need for strict comparison? It is like in this case it is just a matter of style I think. – Giorgi Nakeuri Dec 14 '15 at 07:51
  • @mokiSRB, as per your input x==y is also false – Harpreet Singh Dec 14 '15 at 07:53
  • 10
    It could be that Flanagan just prefers `!==` checks over `!=` checks. As far as I'm aware there's no other value where `x != x`. But there are two distinct groups of JavaScript developers: those who prefer `!=` and those who prefer `!==`, be it for speed, clarity, expressiveness, etc. – Steve Klösters Dec 14 '15 at 07:56
  • For a check which is comparing two valus from the same type `==` or `!=` always should return the same result as `===` and `!==`. The problems appear when comparing different types. – AntiHeadshot Dec 14 '15 at 08:02
  • 31
    Why use loose comparison when strict comparison behaves the same way? – Ry- Dec 14 '15 at 08:06
  • @GiorgiNakeuri NaN is the unique type of object that is not equal to it self. – Raulucco Dec 14 '15 at 08:21
  • 3
    @Raulucco: `NaN` isn't a unique type, it's a number. It's a unique *value* that is not equal to itself. – T.J. Crowder Dec 14 '15 at 09:15
  • 8
    The title seems to be misleading people. I'd suggest changing it to something like "Is x != x ever different from x !== x?" – T.J. Crowder Dec 14 '15 at 09:16
  • 1
    @GiorgiNakeuri `==` and `===` are **not** just style preference. They serve different purposes for those who understand how they work. They**don't** behave the same, but sometimes have the same results. My answer gave several examples where they're different. David Flanagan is also wrong for using either `==` or `===` for NaN comparison anyway. NaN is a unique value that is not equal to anything--including itself--so even when `x` *is* NaN, `x == NaN` and `x === NaN` will still be false. That's why the negation appears to behave the same, it's always false unless you use `isNaN()`. – femmestem Dec 14 '15 at 09:30
  • 6
    @femmestem: Giorgi said "in this case" it's a matter of style. And he's correct in that. It *isn't* style when the types of the operands are different, but it *is* style when they're the same. Separately: Flanagan is doing those comparisons wth `===` with NaN *to make the point* that NaN is not equal to itself. He's not "wrong," he's doing it as a teaching exercise, demonstrating that it doesn't work. – T.J. Crowder Dec 14 '15 at 09:39
  • @GiorgiNakeuri I just came across this article after reading your question, point #4 addresses equality operators and might interest you. Pretty much the same as T.J. Crowder was stating in his answer: https://www.toptal.com/javascript/10-most-common-javascript-mistakes – Pitt Mar 25 '16 at 16:38

5 Answers5

129

First, let me point out that NaN is a very special value: By definition, it's not equal to itself. That comes from the IEEE-754 standard that JavaScript numbers draw on. The "not a number" value is never equal to itself, even when the bits are an exact match. (Which they aren't necessarily in IEEE-754, it allows for multiple different "not a number" values.) Which is why this even comes up; all other values in JavaScript are equal to themselves, NaN is just special.

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

No, you're not. The only difference between !== and != is that the latter will do type coercion if necessary to get the types of the operands to be the same. In x != x, the types of the operands are the same, and so it's exactly the same as x !== x.

This is clear from the beginning of the definition of the 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. ...

The first two steps are basic plumbing. So in effect, the very first step of == is to see if the types are the same and, if so, to do === instead. != and !== are just negated versions of that.

So if Flanagan is correct that only NaN will give true for x !== x, we can be sure that it's also true that only NaN will give true for x != x.

Many JavaScript programmers default to using === and !== to avoid some pitfalls around the type coercion the loose operators do, but there's nothing to read into Flanagan's use of the strict vs. loose operator in this case.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I have reread `4.9.1 - Equality and Inequality Operators` section and this seems to be the answer. The key point for `===` comparison is: `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 Dec 14 '15 at 09:27
  • @GiorgiNakeuri: I'm not sure what 4.9.1 you're referring to, perhaps Flanagan's book? But that's basically saying what the quote from the spec above is saying, yes. – T.J. Crowder Dec 14 '15 at 09:32
  • Yes, it is from Flanagan's 6th edition. Thank's for the link on specs. – Giorgi Nakeuri Dec 14 '15 at 09:35
  • 2
    I am accepting this because this answers my question in formalized and precise fashion. Thank you for the explanations! – Giorgi Nakeuri Dec 14 '15 at 10:01
  • with es modules and live bindings, `import a from 'a'; console.log(a !== a)` can return true for non NaN values – qwertymk Dec 14 '15 at 17:42
  • 1
    @Moshe: What do you mean by "live bindings"? (The term doesn't appear in the spec.) Do you mean something like [GOTO 0's example](http://stackoverflow.com/a/34264110/157247) where `a` is actually a function and doesn't return the same value twice? That's not the same thing as a **value** for which `!==` would be true, which is what the OP asked about. It's just a function that returns different values. `foo() !== foo()` isn't necessarly true either, since `foo` might return different values on each call. – T.J. Crowder Dec 14 '15 at 18:30
  • @T.J.Crowder something like this: It's a fun WAT moment: http://babeljs.io/repl/#?experimental=false&evaluate=false&loose=false&spec=false&code=%2F%2F%20foo.js%0AObject.defineProperty(exports%2C%20'foo'%2C%7B%0A%20%20get%3A%20()%20%3D%3E%20Math.random()%2C%0A%7D)%3B%0A%0A%0A%0A%2F%2F%20bar.js%0Aimport%20%7B%20foo%20%7D%20from%20'.%2Ffoo'%3B%0A%0Aconsole.log(foo%20!%3D%3D%20foo) – qwertymk Dec 14 '15 at 20:45
  • 1
    @Moshe Well that's a super-nasty way to mess with properties and getters. But it does appear to be pretty much the same as GOTO 0's example, just with an extra layer of indirection. – JAB Dec 14 '15 at 21:18
  • I think this answer should clarify that (NaN !== NaN (even if its the same variable being compared to itself)) and that it is a bad example of how comparison operators actually work. NaN should overall be avoided because of its confusing implementation. (typeof NaN === "number"), etc – Sleavely Mar 25 '16 at 17:12
  • "it allows for multiple different "not a number" values." -- Can you provide a link to support this confusing statement? – Dmitri Zaitsev Jun 02 '16 at 10:27
  • From http://www.ecma-international.org/ecma-262/5.1/#sec-8.5: **to ECMAScript code, all NaN values are indistinguishable from each other.** So there are no multiple values. – Dmitri Zaitsev Jun 02 '16 at 10:43
  • @DmitriZaitsev: It's in the IEEE-754 specification, which you can readily find (but requires payment). It's also covered in the [IEEE-754](https://en.wikipedia.org/wiki/IEEE_floating_point#cite_note-19) and [NaN](https://en.wikipedia.org/wiki/NaN) Wikipedia pages. Regarding your quote of the JS spec, note the sentence where I mention them: *"(Which they aren't necessarily **in IEEE-754**, it allows for multiple different "not a number" values.)"* And just because they're indistinguishable in JS, it doesn't mean there isn't more than one, particularly if they're coming from outside the JS env. – T.J. Crowder Jun 04 '16 at 08:58
  • Any example how two different values can come up? – Dmitri Zaitsev Jun 07 '16 at 06:56
  • @DmitriZaitsev: Any number received from the host environment might have any of the 2^53 different bit patterns allowed for `NaN`, perhaps `0111 1111 1111 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000` or `0111 1111 1111 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111`. For that matter, a JS engine is free to have calculations that result in different kinds of `NaN`s -- and may well, if it uses the CPU's floating point ops. We have no way of telling, of course, because JS treats them all the same despite the fact that they are distinct in IEEE-754. – T.J. Crowder Jun 07 '16 at 08:11
38

For purposes of NaN, != and !== do the same thing.

However, many programmers avoid == or != in JavaScript. For example, Douglas Crockford considers them among the "bad parts" of the JavaScript language because they behave in unexpected and confusing ways:

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 !==.

Community
  • 1
  • 1
jkdev
  • 11,360
  • 15
  • 54
  • 77
  • 2
    The question isn't about NaN (despite the title). The question is *"am I missing some value in JavaScript that will return true for x !== x and false for x != x?"* – T.J. Crowder Dec 14 '15 at 09:12
  • @T.J.Crowder Two questions, really. The first question is "Is it safe to use both versions" and the answer is that both versions are equivalent. I do like your "under-the-hood" answer which explains everything in detail. – jkdev Dec 14 '15 at 10:08
22

Just for fun, let me show you an artificial example where x is not NaN but the operators behave differently anyway. First define:

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

Then we have

x != x // false

but

x !== x // true
GOTO 0
  • 42,323
  • 22
  • 125
  • 158
  • 9
    Ha! :-) But that's effectively `foo() != foo()` where foo returns 1 then 2. E.g., the *values* aren't the same, it's just comparing different values. – T.J. Crowder Dec 14 '15 at 10:09
2

I just want to point out NaN is not the only thing that produces x !== x without using the global object. There are lots of clever ways to trigger this behavior. Here is one using getters:

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

As other answers point out, == performs type coersion, but in as in other languages and par the standard - NaN indicates a computation failure, and for good reasons is not equal to itself.

For some reason beyond me people ocnsider this a problem with JS but most languages that have doubles (namely, C, Java, C++, C#, Python and others) exhibit this exact behavior and people are just fine with it.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
0

As sometimes, images are better than words, check this table (which is the reason for me to make this an answer instead a comment is because it gets better visibility).

There you can see that strict equality comparison (===) only returns true if type and content match, so

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

While abstract equality comparison (==) checks only the content* by converting types and then strictly comparing them:

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

Though it's not clear, without consulting ECMA, what JavaScript considers when comparing, in a way that the code bellow evaluates to true.

 var howAmISupposedToKnowThat = [] == false; //true
MVCDS
  • 380
  • 4
  • 14