Why is isNaN(null) == false in JS? - javascript

This code in JS gives me a popup saying "i think null is a number", which I find slightly disturbing. What am I missing?
if (isNaN(null)) {
alert("null is not a number");
} else {
alert("i think null is a number");
}
I'm using Firefox 3. Is that a browser bug?
Other tests:
console.log(null == NaN); // false
console.log(isNaN("text")); // true
console.log(NaN == "text"); // false
So, the problem seems not to be an exact comparison with NaN?
Edit: Now the question has been answered, I have cleaned up my post to have a better version for the archive. However, this renders some comments and even some answers a little incomprehensible. Don't blame their authors. Among the things I changed was:
Removed a note saying that I had screwed up the headline in the first place by reverting its meaning
Earlier answers showed that I didn't state clearly enough why I thought the behaviour was weird, so I added the examples that check a string and do a manual comparison.

I believe the code is trying to ask, "is x numeric?" with the specific case here of x = null. The function isNaN() can be used to answer this question, but semantically it's referring specifically to the value NaN. From Wikipedia for NaN:
NaN (Not a Number) is a value of the numeric data type representing an undefined or unrepresentable value, especially in floating-point calculations.
In most cases we think the answer to "is null numeric?" should be no. However, isNaN(null) == false is semantically correct, because null is not NaN.
Here's the algorithmic explanation:
The function isNaN(x) attempts to convert the passed parameter to a number1 (equivalent to Number(x)) and then tests if the value is NaN. If the parameter can't be converted to a number, Number(x) will return NaN2. Therefore, if the conversion of parameter x to a number results in NaN, it returns true; otherwise, it returns false.
So in the specific case x = null, null is converted to the number 0, (try evaluating Number(null) and see that it returns 0,) and isNaN(0) returns false. A string that is only digits can be converted to a number and isNaN also returns false. A string (e.g. 'abcd') that cannot be converted to a number will cause isNaN('abcd') to return true, specifically because Number('abcd') returns NaN.
In addition to these apparent edge cases are the standard numerical reasons for returning NaN like 0/0.
As for the seemingly inconsistent tests for equality shown in the question, the behavior of NaN is specified such that any comparison x == NaN is false, regardless of the other operand, including NaN itself1.

I just ran into this issue myself.
For me, the best way to use isNaN is like so
isNaN(parseInt(myInt))
taking phyzome's example from above,
var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]
x.map( function(n){ return isNaN(parseInt(n))})
[true, true, true, true, true, false, false, false, true, true, false]
( I aligned the result according to the input, hope it makes it easier to read. )
This seems better to me.

(My other comment takes a practical approach. Here's the theoretical side.)
I looked up the ECMA 262 standard, which is what Javascript implements. Their specification for isNan:
Applies ToNumber to its argument, then returns true if the result is NaN, and otherwise returns false.
Section 9.3 specifies the behavior of ToNumber (which is not a callable function, but rather a component of the type conversion system). To summarize the table, certain input types can produce a NaN. These are type undefined, type number (but only the value NaN), any object whose primitive representation is NaN, and any string that cannot be parsed. This leaves undefined, NaN, new Number(NaN), and most strings.
Any such input that produces NaN as an output when passed to ToNumber will produce a true when fed to isNaN. Since null can successfully be converted to a number, it does not produce true.
And that is why.

This is indeed disturbing. Here is an array of values that I tested:
var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]
It evaluates (in the Firebug console) to:
,NaN,blah,NaN,,0,0,1,Infinity,-Infinity,5
When I call x.map(isNaN) (to call isNaN on each value), I get:
true,true,true,true,false,false,false,false,false,false,false
In conclusion, isNaN looks pretty useless! (Edit: Except it turns out isNaN is only defined over Number, in which case it works just fine -- just with a misleading name.)
Incidentally, here are the types of those values:
x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number

Null is not NaN, as well as a string is not NaN. isNaN() just test if you really have the NaN object.

In ES5, it defined as isNaN (number) returns true if the argument coerces to NaN, and otherwise returns false.
If ToNumber(number) is NaN, return true.
Otherwise, return false.
And see the The abstract operation ToNumber convertion table. So it internally js engine evaluate ToNumber(Null) is +0, then eventually isNaN(null) is false

I'm not exactly sure when it comes to JS but I've seen similar things in other languages and it's usually because the function is only checking whether null is exactly equal to NaN (i.e. null === NaN would be false). In other words it's not that it thinks that null is in fact a number, but it's rather that null is not NaN. This is probably because both are represented differently in JS so that they won't be exactly equal, in the same way that 9 !== '9'.

Note:
"1" == 1 // true
"1" === 1 // false
The == operator does type-conversion, while === does not.
Douglas Crockford's website, a Yahoo! JavaScript evangelist, is a great resource for stuff like this.

(NaN == null) // false
(NaN != null) // true
Funny though:
(NaN == true) // false
(NaN == false) // false
(NaN) // false
(!NaN) // true
Aren't (NaN == false) and (!NaN) identical?

Related

Why does an empty filter act as a Boolean? [duplicate]

What are the values in JavaScript that are 'falsey', meaning that they evaluate as false in expressions like if(value), value ? and !value?
There are some discussions of the purpose of falsey values on Stack Overflow already, but no exhaustive complete answer listing what all the falsey values are.
I couldn't find any complete list on MDN JavaScript Reference, and I was surprised to find that the top results when looking for a complete, authoritative list of falsey values in JavaScript were blog articles, some of which had obvious omissions (for example, NaN), and none of which had a format like Stack Overflow's where comments or alternative answers could be added to point out quirks, surprises, omissions, mistakes or caveats. So, it seemed to make sense to make one.
Falsey values in JavaScript
false
Zero of Number type: 0 and also -0, 0.0, and hex form 0x0 (thanks RBT)
Zero of BigInt type: 0n and 0x0n (new in 2020, thanks GetMeARemoteJob)
"", '' and `` - strings of length 0
null
undefined
NaN
document.all (in HTML browsers only)
This is a weird one. document.all is a falsey object, with typeof as undefined. It was a Microsoft-proprietory function in IE before IE11, and was added to the HTML spec as a "willful violation of the JavaScript specification" so that sites written for IE wouldn't break on trying to access, for example, document.all.something; it's falsy because if (document.all) used to be a popular way to detect IE, before conditional comments. See Why is document.all falsy? for details
"Falsey" simply means that JavaScript's internal ToBoolean function returns false. ToBoolean underlies !value, value ? ... : ...; and if (value). Here's its official specification (2020 working draft) (the only changes since the very first ECMAscript specification in 1997 are the addition of ES6's Symbols, which are always truthy, and BigInt, mentioned above:
Argument type
Result
Undefined
Return false.
Null
Return false.
Boolean
Return argument.
Number
If argument is +0, -0, or NaN, return false; otherwise return true.
String
If argument is the empty String (its length is zero), return false; otherwise return true.
BigInt
If argument is 0n, return false; otherwise return true.
Symbol
Return true.
Object
Return true.
Comparisons with == (loose equality)
It's worth talking about falsy values' loose comparisons with ==, which uses ToNumber() and can cause some confusion due to the underlying differences. They effectively form three groups:
false, 0, -0, "", '' all match each other with ==
e.g. false == "", '' == 0 and therefore 4/2 - 2 == 'some string'.slice(11);
null, undefined match with ==
e.g. null == undefined but undefined != false
It's also worth mentioning that while typeof null returns 'object', null is not an object, this is a longstanding bug/quirk that was not fixed in order to maintain compatibility. It's not a true object, and objects are truthy (except for that "wilful violation" document.all when Javascript is implemented in HTML)
NaN doesn't match anything, with == or ===, not even itself
e.g. NaN != NaN, NaN !== NaN, NaN != false, NaN != null
With "strict equality" (===), there are no such groupings. Only false === false.
This is one of the reasons why many developers and many style guides (e.g. standardjs) prefer === and almost never use ==.
Truthy values that actually == false
"Truthy" simply means that JavaScript's internal ToBoolean function returns true. A quirk of Javascript to be aware of (and another good reason to prefer === over ==): it is possible for a value to be truthy (ToBoolean returns true), but also == false.
You might think if (value && value == false) alert('Huh?') is a logical impossibility that couldn't happen, but it will, for:
"0" and '0' - they're non-empty strings, which are truthy, but Javascript's == matches numbers with equivalent strings (e.g. 42 == "42"). Since 0 == false, if "0" == 0, "0" == false.
new Number(0) and new Boolean(false) - they're objects, which are truthy, but == sees their values, which == false.
0 .toExponential(); - an object with a numerical value equivalent to 0
Any similar constructions that give you a false-equaling value wrapped in a type that is truthy
[], [[]] and [0] (thanks cloudfeet for the JavaScript Equality Table link)
Some more truthy values
These are just a few values that some people might expect to be falsey, but are actually truthy.
-1 and all non-zero negative numbers
' ', " ", "false", 'null'... all non-empty strings, including strings that are just whitespace
Anything from typeof, which always returns a non-empty string, for example:
typeof null (returns a string 'object' due to a longstanding bug/quirk)
typeof undefined (returns a string 'undefined')
Any object (except that "wilful violation" document.all in browsers). Remember that null isn't really an object, despite typeof suggesting otherwise. Examples:
{}
[]
function(){} or () => {} (any function, including empty functions)
Error and any instance of Error
Any regular expression
Anything created with new (including new Number(0) and new Boolean(false))
Any Symbol
true, 1, "1" and [1] return true when compared to each other with ==.
Don't forget about the non-empty string "false" which evaluates to true
Just to add to #user568458's list of falsy values:
In addition to integer number 0, the decimal number 0.0, 0.00 or any such zeroish number is also a falsy value.
var myNum = 0.0;
if(myNum){
console.log('I am a truthy value');
}
else {
console.log('I am a falsy value');
}
Above code snippet prints I am a falsy value
Similarly hex representation of the number 0 is also a falsy value as shown in below code snippet:
var myNum = 0x0; //hex representation of 0
if(myNum){
console.log('I am a truthy value');
}
else {
console.log('I am a falsy value');
}
Above code snippet again prints I am a falsy value.
Addition to the topic, as of ES2020 we have a new value which is falsy, it's BigInt zero (0n):
0n == false // true
-0n == false // true
0n === false // false
-0n === false // false
So with this, we now have 7 "falsy" values in total (not including document.all as mentioned by user above since it's part of DOM and not JS).

All falsey values in JavaScript

What are the values in JavaScript that are 'falsey', meaning that they evaluate as false in expressions like if(value), value ? and !value?
There are some discussions of the purpose of falsey values on Stack Overflow already, but no exhaustive complete answer listing what all the falsey values are.
I couldn't find any complete list on MDN JavaScript Reference, and I was surprised to find that the top results when looking for a complete, authoritative list of falsey values in JavaScript were blog articles, some of which had obvious omissions (for example, NaN), and none of which had a format like Stack Overflow's where comments or alternative answers could be added to point out quirks, surprises, omissions, mistakes or caveats. So, it seemed to make sense to make one.
Falsey values in JavaScript
false
Zero of Number type: 0 and also -0, 0.0, and hex form 0x0 (thanks RBT)
Zero of BigInt type: 0n and 0x0n (new in 2020, thanks GetMeARemoteJob)
"", '' and `` - strings of length 0
null
undefined
NaN
document.all (in HTML browsers only)
This is a weird one. document.all is a falsey object, with typeof as undefined. It was a Microsoft-proprietory function in IE before IE11, and was added to the HTML spec as a "willful violation of the JavaScript specification" so that sites written for IE wouldn't break on trying to access, for example, document.all.something; it's falsy because if (document.all) used to be a popular way to detect IE, before conditional comments. See Why is document.all falsy? for details
"Falsey" simply means that JavaScript's internal ToBoolean function returns false. ToBoolean underlies !value, value ? ... : ...; and if (value). Here's its official specification (2020 working draft) (the only changes since the very first ECMAscript specification in 1997 are the addition of ES6's Symbols, which are always truthy, and BigInt, mentioned above:
Argument type
Result
Undefined
Return false.
Null
Return false.
Boolean
Return argument.
Number
If argument is +0, -0, or NaN, return false; otherwise return true.
String
If argument is the empty String (its length is zero), return false; otherwise return true.
BigInt
If argument is 0n, return false; otherwise return true.
Symbol
Return true.
Object
Return true.
Comparisons with == (loose equality)
It's worth talking about falsy values' loose comparisons with ==, which uses ToNumber() and can cause some confusion due to the underlying differences. They effectively form three groups:
false, 0, -0, "", '' all match each other with ==
e.g. false == "", '' == 0 and therefore 4/2 - 2 == 'some string'.slice(11);
null, undefined match with ==
e.g. null == undefined but undefined != false
It's also worth mentioning that while typeof null returns 'object', null is not an object, this is a longstanding bug/quirk that was not fixed in order to maintain compatibility. It's not a true object, and objects are truthy (except for that "wilful violation" document.all when Javascript is implemented in HTML)
NaN doesn't match anything, with == or ===, not even itself
e.g. NaN != NaN, NaN !== NaN, NaN != false, NaN != null
With "strict equality" (===), there are no such groupings. Only false === false.
This is one of the reasons why many developers and many style guides (e.g. standardjs) prefer === and almost never use ==.
Truthy values that actually == false
"Truthy" simply means that JavaScript's internal ToBoolean function returns true. A quirk of Javascript to be aware of (and another good reason to prefer === over ==): it is possible for a value to be truthy (ToBoolean returns true), but also == false.
You might think if (value && value == false) alert('Huh?') is a logical impossibility that couldn't happen, but it will, for:
"0" and '0' - they're non-empty strings, which are truthy, but Javascript's == matches numbers with equivalent strings (e.g. 42 == "42"). Since 0 == false, if "0" == 0, "0" == false.
new Number(0) and new Boolean(false) - they're objects, which are truthy, but == sees their values, which == false.
0 .toExponential(); - an object with a numerical value equivalent to 0
Any similar constructions that give you a false-equaling value wrapped in a type that is truthy
[], [[]] and [0] (thanks cloudfeet for the JavaScript Equality Table link)
Some more truthy values
These are just a few values that some people might expect to be falsey, but are actually truthy.
-1 and all non-zero negative numbers
' ', " ", "false", 'null'... all non-empty strings, including strings that are just whitespace
Anything from typeof, which always returns a non-empty string, for example:
typeof null (returns a string 'object' due to a longstanding bug/quirk)
typeof undefined (returns a string 'undefined')
Any object (except that "wilful violation" document.all in browsers). Remember that null isn't really an object, despite typeof suggesting otherwise. Examples:
{}
[]
function(){} or () => {} (any function, including empty functions)
Error and any instance of Error
Any regular expression
Anything created with new (including new Number(0) and new Boolean(false))
Any Symbol
true, 1, "1" and [1] return true when compared to each other with ==.
Don't forget about the non-empty string "false" which evaluates to true
Just to add to #user568458's list of falsy values:
In addition to integer number 0, the decimal number 0.0, 0.00 or any such zeroish number is also a falsy value.
var myNum = 0.0;
if(myNum){
console.log('I am a truthy value');
}
else {
console.log('I am a falsy value');
}
Above code snippet prints I am a falsy value
Similarly hex representation of the number 0 is also a falsy value as shown in below code snippet:
var myNum = 0x0; //hex representation of 0
if(myNum){
console.log('I am a truthy value');
}
else {
console.log('I am a falsy value');
}
Above code snippet again prints I am a falsy value.
Addition to the topic, as of ES2020 we have a new value which is falsy, it's BigInt zero (0n):
0n == false // true
-0n == false // true
0n === false // false
-0n === false // false
So with this, we now have 7 "falsy" values in total (not including document.all as mentioned by user above since it's part of DOM and not JS).

why null==undefined is true in javascript

If we alert(null==undefined) it outputs to true.
What is the logical reason for this.
Is this something that is hard coded in javascript or is there an explanation for this.
The language specification explicitly says:
If x is null and y is undefined, return true
I'm not aware of any records of the language design process that explain the reasoning for that decision, but == has rules for handling different types, and "null" and "undefined" are both things that mean "nothing", so having them be equal makes intuitive sense.
(If you don't want type fiddling, use === instead).
Using the double-equal operator forces Javascript to do type coercion.
In other words, when you do x == y, if x and y are not of the same type, JavaScript will cast one value to another before comparing, like if string and number are compared, the string is always cast into a number and then compared
For this reason, many comparisons of mixed types in JavaScript can result in results that may be unexpected or counter-intuitive.
If you want to do comparisons in JavaScript, it is usually a better idea to use the triple-equal operator === rather than double-equal. This does not do a type coercion; instead if the types are different, it returns false. This is more usually what you need.
You should only use double-equal if you are absolutely certain that you need it.
For the same reason that 0 == "0" - javascript is loosely typed - if something can be converted to something else then it will be unless you use ===
alert(null===undefined);
Will give you false.
As for why these particular conversions happen - the answer is quite simply "the spec says that is what should happen". There doesn't need to be a reason other than "because it says so" for why programming language behave in certain ways.
Edit: Slightly better answer - in Javascript, certain objects/values are 'truthy' or 'falsey' when converted to a boolean. 0 (integer zero), "0" (character zero in a string), "" (empty string) are all false. If there isn't a better comparison to use then the boolean operation applies.
This is why "0" is not equal to an empty string, but both "0" and "" are both equal to false.
we know,
If x is null and y is undefined, return true
undefined == null => true, reason might be both are converted to boolean, as we know javascript performs the type conversion. so that will be resulting the null and undefined converted to false and false == false is true
A better explanation...
In the case of "==" or Loose Equality Operator, if one of the operands is null or undefined and the other is null or undefined, always return true. Otherwise return false. Unlike what other posters falsely state, these are not converted or coerced into new types when using equality operators, but simply follow the rule above.
// TRUE - loose equality operator says use the null vs. undefined rule above which equates them
console.log(null == undefined);
// FALSE - strict equality operator says these are not of the same type, so always return false
console.log(null === undefined);
The == comparison operator doesn't check the types. null and undefined both return false. That's why your code is actually checking if false is equal to false.
> null == undefined;
< true
> false == false
< true
However their types are not equal.
> typeof undefined;
< "undefined"
> typeof null;
< "object"
Because of that, the next statement will return false, as the === comparison operator checks both the types and their value.
> undefined === null;
< false

Is the conditional "if(x)" different than "if(x == true)"?

I'm wondering what the core difference is between the conditional syntax below?
if (something) {
// do something
}
vs.
if (something == true) {
// do something
}
Are there any differences?
Edit: I apologize. I made a typo when the question was asked. I did not mean to put a triple equals sign. I know that triple equals is a strict operator. I was meaning to ask if '==' is the equivalent of if (something).
The difference is that in if(something), something is evaluated as boolean. It is basically
if(ToBoolean(something))
where ToBoolean is an internal function that is called to convert the argument to a boolean value. You can simulate ToBoolean with a double negation: !!something.
In the second case, both operands are (eventually) converted to numbers first, so you end up with
if(ToNumber(something) == ToNumber(true))
which can lead to very different results. Again, ToNumber is an internal function. It can be simulated (to some degree) using the unary plus operator: +something == +true. In the actual algorithm, something is first passed ToPrimitive if something is an object.
Example:
Assume that
var something = '0'; // or any other number (not 0) / numeric string != 1
if(something) will be true, since '0' is a non-empty string.
if(something == true) will be false, since ToNumber('0') is 0, ToNumber(true) is 1 and 0 == 1 is false.
EDIT: Below only holds true for the original question, in which the === operator was used.
The first one will execute the body of the if-statement if something is "truthy" while the second will only execute it if it is equal in type and value to true.
So, what is "truthy"? To understand that, you need to know what is its opposite: falsey. All values in JavaScript will be coerced into a Boolean value if placed in a conditional expression. Here's a list of falsey values:
false
0 (zero)
"" (empty string)
null
undefined
NaN
All other values are truthy, though I've probably missed some obscure corner case that someone will point out in the comments.
Here's my answer to the updated question:
The conditional if (something) and if (something == true) are equivalent, though the second is redundant. something will be type coerced in the same way in either case. This is wrong. See Felix Kling's answer.
if(something) is equivalent to if(someting == true).
The == operator checks for equality while === checks for sameness. In this case, any truthy value will cause the condition to be met for the first one, but only true will cause the condition to be met for the second one.
EDIT: Felix Kling's answer is correct. Please reference that instead.
Now that the question has changed from === to ==, no, there is no practical difference.
There are a couple ways to look at it. The first example evaluates to see if "something" has a true-like or positive value. So as long as it is not 0, negative, null, or empty it should evaluate the contents of that if statement.
In your second statement you are testing to see if "something" is the equivalent of boolean true. Another words "TRUE" or 1. You could also do a "===" comparison so that it has to be identical to what your comparing it to. So in this case if you did something === true then "something" would have to be boolean true, the value of 1 would not suffice.
There is no difference between the two conditions thing == true and just thing.
There is a large difference between thing === true and just thing, however.
In javascript, values are coerced to a boolean when they are put in a condition. This means all values of all types must be able to be coerced to either true or false. A value that coerces to true is generally called "truthy", and a value that coerces to false is called "falsey".
The "falsey" values are as follows:
NaN (not a number)
'' (empty string)
undefined
null
0 (numeric 0)
Everything else evaluates to true when coerced. This jsFiddle will help you keep track of what is "truthy" and what is "falsey".
The identity operator (===) does NOT perform any type coercion: if the types are different, the comparison immediately fails.

How to check if variable is null, but allow 1 and 0?

I use the following code currently
if (oldValue) ...
It works well in case oldValue is null, but in case it is 0, it also returns false, when I expect true. So, how should I check for null value? I was thinking about
if (oldValue!=null) ...
but it doesn't work as I've expected.
To answer your question directly, if your allowed values are 0 and 1 the if statement should look like:
if (0 === oldValue || 1 === oldValue) {
...
}
This is (in my opinion) the clearest way to state which values are allowed.
For a more details explanation see below:
This has to do with truthy and falsy values.
null evaluates to false, as do 0, "", undefined and NaN, these are called falsy values.
Likewise, some values evaluate to true. Such as: "a string", "0" (non empty string "0"), any number other than 0 (including negative numbers), Arrays and Objects (even empty ones). These are truthy values.
There are some unexpected results:
"" == false // true
0 == false // true
but:
NaN == false // false
null == false // false
In practice you should always use the identity operator === instead of equality (==). This ensures that you know what type your variable is expected to be (String, Number, Object) and what the exceptional states are.
Some examples:
If you're getting a value from an input field it will always be a string - the special case is the empty string. Coincidentally this is a falsy value.
If you're counting elements and you need to do something special in case there are no elements - the special case is 0. Coincidentally this is a falsy value.
If you're trying to parse a number from a string using parseInt or parseFloat - the special case NaN (check with isNaN()). Coincidentally this is a falsy value.
If you're checking if a substring occurs within a string using indexOf - the special case is -1 (because 0 is a valid index). This is not a falsy value, but if(str.indexOf(substr)) is most certainly wrong because it is unclear the author knows about the possibly allowed value 0 (which is falsy)
The point here is: the special cases usually are well defined. Harnessing that allows you to always use the identity operator ===. The equality operator == and falsiness is a common source of bugs.
For reference:
"" === false // false
0 === false // false
NaN === false // false
null === false // false
false === false // true (of course)
NaN === NaN // strange, but makes sense
"a" === "a" // yay!
Short answer: If you want to test exactly whether the variable does not have the value null, then change your code to:
if (oldValue !== null) ...
(However, you should think about whether the oldValue might be undefined rather than null, which would have to be a separate case.)
See Frits van Campen's answer for the details of the difference between ==/!= and ===/!==.

Categories

Resources