Why does isNaN(" ") (string with spaces) equal false?
Asked Answered
A

25

193

In JavaScript, why does isNaN(" ") evaluate to false, but isNaN(" x") evaluate to true?

I’m performing numerical operations on a text input field, and I’m checking if the field is null, "", or NaN. When someone types a handful of spaces into the field, my validation fails on all three, and I’m confused as to why it gets past the isNaN check.

Aguilar answered 5/5, 2009 at 15:21 Comment(5)
Hm... not quite sure where the other half of the subject went. It's supposed to read, "JavaScript: Why does isNaN(" ") evaluate to false?"Aguilar
Jes, that's the behavior (empty or space returns false for isNaN), but I didn't find the exact specs of this function.Acutance
Here's a question which answers this: https://mcmap.net/q/100706/-why-is-isnan-null-false-in-jsAcutance
Javascript on these issues seems like voodoo! You never know and the explanation is always quite complex. "" == false // true and isNaN(" ") // falseNitrometer
Use Number.isNaN instead.Wildermuth
B
186

JavaScript interprets an empty string as a 0, which then fails the isNAN test. You can use parseInt on the string first which won't convert the empty string to 0. The result should then fail isNAN.

Blinkers answered 5/5, 2009 at 15:27 Comment(11)
But parseInt("123abcd") returns 123, which means isNaN(parseInt("123abcd")) will return false while it should return true!Reporter
So how about (IsNaN(string) || isNaN(parseInt(string)))Adytum
There's 2 steps in interpreting isNaN(arg). 1) Convert arg to number, 2) Check if that number is the numerical value NaN. That helped me understand it better.Aleph
@Antonio_Haley Wait a minute, I don't get it. If "JavaScript interprets an empty string as a 0", why does parseInt("") return NaN?Dayna
@Jean-François You're right, the more correct statement would be "isNaN interprets an empty string as 0", not JavaScript itself.Blinkers
How about a separate empty string check: isNaN(value) || value === '' Also seems to be more performant: jsperf.com/empty-string-is-nanLiberal
The string isn't empty though. It's a string of whitespace.Lingulate
@Pawan Nogariya parseInt is for grabbing the number part off the start of a string which in the case of "123abcd" is 123 so you got an actual number being returned. so while "123abcd" by itself would be NaN parseInt("123abcd") is not NaN as that function call does indeed return a number so thus why it returns false as 123 is a number.Masquer
@Adytum is right, except it should be && instead of ||: (isNaN(string) && isNaN(parseInt(string)))Bugs
Great answer. I had the same problem of a number input always returning false when I entered a string or number e.g. isNaN(2j) && isNaN("") && isNaN(2) //gave result as false with oninput function. I fixed this with your answer by first parsing the elements' value to float or integer before entering the value to be validated as attribute to isNaN() function.Coal
And the terrible thing is, isNaN(parseFloat("")) != isNaN(""). parseFloat("") returns NaN but isNaN("") still says false!!Siusiubhan
A
91

You may find this surprising or maybe not, but here is some test code to show you the wackyness of the JavaScript engine.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

so this means that

" " == 0 == false

and

"" == 0 == false

but

"" != " "

Have fun :)

Awl answered 5/5, 2009 at 15:34 Comment(9)
+1 Great post. Can you add how the triple equals (=== and !==) operator fits here?Ewan
You should try NaN===NaN or NaN==NaN;-) I don't know if all this means the javascript engine is wacky or that javascript is bad for wacky programmers though.Sophrosyne
@Kooilnc the fact that NaN != NaN is, actually, a good choice for once. The idea is that NaN is almost always a result of a computation that went different than how the programmer intended, and to assume that the results of two computations that went "wrong" are equal is pretty dangerous, I'd say.Halflife
@Kooilnc not to take away even slightly from the wackiness of javascript, but these NaNs are just obeying the IEEE 754 floating point standard. You can read ALL about it as usual on the big W: en.wikipedia.org/wiki/NaNMuncy
@NickBerardi F'ing LOL! I'm sooo glad I saw this post. Helped me figure out why the isNaN function is so retarded. I will be stripping it from my not-fully-developed code right now, and will likely never use it again. I will validate for null, "", and " " myself. Thanks!Sines
Great post but doesn't explain "why".Aleph
And that is why you should (almost) always use ===.Embattle
what's really whacky is what follows: " " == false evaluates to true, BUT " " || false evaluates to " ".Vatican
Abstract equality is irrelevant here. isNaN performs ToNumber of its argument, which means that isNaN(arg) and isNaN(Number(arg)) are equivalent. @Sines If you want an isNaN that doesn’t perform this coercion, use Number.isNaN.Wildermuth
P
20

To understand it better, please open Ecma-Script spec pdf on page 43 "ToNumber Applied to the String Type"

if a string has a numerical syntax, which can contain any number of white-space characters, it can be converted to Number type. Empty string evaluates to 0. Also the string 'Infinity' should give

isNaN('Infinity'); // false
Phineas answered 5/5, 2009 at 15:32 Comment(0)
E
13

Try using:

alert(isNaN(parseInt("   ")));

Or

alert(isNaN(parseFloat("    ")));
Ewan answered 5/5, 2009 at 15:27 Comment(1)
hi sir, isNaN(parseInt("123a")) : will return 123 so ur solution will not work , if the string contains aplha numericJointless
E
7

From MDN reason for the issue you are facing

When the argument to the isNaN function is not of type Number, the value is first coerced to a Number. The resulting value is then tested to determine whether it is NaN.

You may want to check the following comprehensive answer which covers the NaN comparison for equality as well.

How to test if a JavaScript variable is NaN

Erinnerinna answered 3/5, 2015 at 7:25 Comment(0)
H
6

I think it's because of Javascript's typing: ' ' is converted to zero, whereas 'x' isn't:

alert(' ' * 1); // 0
alert('x' * 1); // NaN
Heparin answered 5/5, 2009 at 15:27 Comment(0)
G
6

The Not-Entirely-Correct Answer

Antonio Haley's highly upvoted and accepted answer here makes a wrong assumption that this process goes through JavaScript's parseInt function:

You can use parseInt on the string ... The result should then fail isNAN.

We can easily disprove this statement with the string "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

With this, we can see that JavaScript's parseInt function returns "123abc" as the number 123, yet its isNaN function tells us that "123abc" isn't a number.

The Correct Answer

ECMAScript-262 defines how the isNaN check works in section 18.2.3.

18.2.3 isNaN (Number)

The isNaN function is the %isNaN% intrinsic object. When the isNaN function is called with one argument number, the following steps are taken:

  1. Let num be ? ToNumber(number).
  2. If num is NaN, return true.
  3. Otherwise, return false.

The ToNumber function it references is also defined in ECMAScript-262's section 7.1.3. In here, we get told how JavaScript handles Strings which are passed in to this function.

The first example given in the question is a string containing nothing but white space characters. This section states that:

A StringNumericLiteral that is empty or contains only white space is converted to +0.

The " " example string is therefore converted to +0, which is a number.

The same section also states:

If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber is NaN.

Without quoting all of the checks contained within that section, the " x" example given in the question falls into the above condition as it cannot be interpreted as a StringNumericLiteral. " x" is therefore converted to NaN.

Guth answered 10/3, 2016 at 12:11 Comment(0)
N
4

The function isNaN("") performs a String to Number type coercion

ECMAScript 3-5 defines the following return values for the typeof operator:

  • undefined
  • object (null, objects, arrays)
  • boolean
  • number
  • string
  • function

Better to wrap our test in a function body:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

This function is not intented to test variable type, instead it tests the coerced value. For instance, booleans and strings are coerced to numbers, so perhaps you may want to call this function as isNumberCoerced()

if there's no need to test for types other than string and number, then the following snippet might be used as part of some condition:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")
Nanette answered 13/9, 2013 at 21:38 Comment(0)
V
3

If you would like to implement an accurate isNumber function, here is one way to do it from Javascript: The Good Parts by Douglas Crockford [page 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}
Vigesimal answered 5/5, 2009 at 15:38 Comment(2)
@Xyan in which case this function isn't very helpful to perform the task the OP was asking to do, which was to inspect a string representation of a number...Gradus
using the so called strict equality operator of any given value against a string literal such as "number" is stupid,Pact
O
3

NaN !== "not a number"

NaN is a value of Number Type

this is a definition of isNaN() in ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

Try to convert any value to Number.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

If you want to determine if the value is NaN, you should try to convert it to a Number value firstly.

Overtime answered 8/8, 2018 at 10:3 Comment(0)
C
2

I suggest you to use the following function if you really want a proper check if it is an integer:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}
Copious answered 26/10, 2010 at 9:39 Comment(0)
T
2

That isNaN(" ") is false is part of the confusing behavior of the isNaN global function due to its coercion of non-numbers to a numeric type.

From MDN:

Since the very earliest versions of the isNaN function specification, its behavior for non-numeric arguments has been confusing. When the argument to the isNaN function is not of type Number, the value is first coerced to a Number. The resulting value is then tested to determine whether it is NaN. Thus for non-numbers that when coerced to numeric type result in a valid non-NaN numeric value (notably the empty string and boolean primitives, which when coerced give numeric values zero or one), the "false" returned value may be unexpected; the empty string, for example, is surely "not a number."

Note also that with ECMAScript 6, there is also now the Number.isNaN method, which according to MDN:

In comparison to the global isNaN() function, Number.isNaN() doesn't suffer the problem of forcefully converting the parameter to a number. This means it is now safe to pass values that would normally convert to NaN, but aren't actually the same value as NaN. This also means that only values of the type number, that are also NaN, return true.

Unfortunately:

Even the ECMAScript 6 Number.isNaN method has its own issues, as outlined in the blog post - Fixing the ugly JavaScript and ES6 NaN problem.

Transmarine answered 29/4, 2015 at 15:22 Comment(1)
That blog post mentions boxed numbers as a problem. No one should use boxed numbers.Wildermuth
S
2

The isNaN function expects a Number as its argument, so arguments of any other type (in your case a string) will be converted to Number before the actual function logic is performed. (Be aware that NaN is also a value of type Number!)

Btw. this is common for all built-in functions - if they expect an argument of a certain type, the actual argument will be converted using the standard conversion functions. There are standard conversions between all the basic types (bool, string, number, object, date, null, undefined.)

The standard conversion for String to Number can be invoked explicit with Number(). So we can see that:

  • Number(" ") evaluates to 0
  • Number(" x") evaluates to NaN

Given this, the result of the isNaN function is completely logical!

The real question is why the standard String-to-Number conversion works like it does. The string-to-number conversion is really intended to convert numeric strings like "123" or "17.5e4" to the equivalent numbers. The conversion first skips initial whitespace (so " 123" is valid) and then tries to parse the rests as a number. If it is not parseable as a number ("x" isn't) then the result is NaN. But there is the explicit special rule that a string which is empty or only whitespace is converted to 0. So this explains the conversion.

Reference: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

Shelbashelbi answered 23/7, 2015 at 9:25 Comment(0)
A
1

I'm not sure why, but to get around the problem you could always trim whitespace before checking. You probably want to do that anyway.

Alliaceous answered 5/5, 2009 at 15:28 Comment(1)
a trimmed empty string also fails isNaN test.Tangled
M
1

I wrote this quick little function to help solve this problem.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

It simply checks for any characters that aren't numeric (0-9), that aren't '-' or '.', and that aren't undefined, null or empty and returns true if there's no matches. :)

Methanol answered 14/12, 2015 at 0:18 Comment(1)
A belated thank you for this; this solved my problem very nicely.Compound
M
1

As other explained the isNaN function will coerce the empty string into a number before validating it, thus changing an empty string into 0 (which is a valid number). However, I found that the parseInt function will return NaN when trying to parse an empty string or a string with only spaces. As such the following combination seems to be working well:

if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

This check will work for positive numbers, negative numbers and numbers with a decimal point, so I believe it covers all common numerical cases.

Mauriciomaurie answered 28/8, 2017 at 3:15 Comment(0)
S
1

I use this

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true
Squabble answered 27/10, 2017 at 12:41 Comment(0)
M
0

This function seemed to work in my tests

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}
Magnien answered 3/2, 2012 at 12:41 Comment(1)
Your whole function can be written: return !(s === "" || s === null || parseInt(s) == 'NaN');Gradus
P
0

What about

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}
Puberty answered 12/7, 2013 at 13:22 Comment(0)
P
0

The JavaScript built-in isNaN function, is - as should be expected by default - a "Dynamic Type Operator". Therefore all values which (during the DTC process) may yield a simple true | false such as "", " ", " 000", cannot be NaN.

Meaning that the argument supplied will first undergo a conversion as in:

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

Explanation:

In the top line of the function body, we are (first) trying to successfully convert the argument into a number object. And (second), using the dot operator we are - for our own convenience - immediately stripping off, the primitive value of the created object.

In the second line, we are taking the value obtained in the previous step, and the advantage of the fact that NaN is not equal to anything in the universe, not even to itself, e.g.: NaN == NaN >> false to finally compare it (for inequality) with itself.

This way the function return will yield true only when, and only if, the supplied argument-return, is a failed attempt of conversion to a number object, i.e., a not-a-number number; e.g., NaN.


isNaNstatic( )

However, for a Static Type Operator - if needed and when needed - we can write a far simpler function such as:

function isNaNstatic(x){   
   return x != x;
}

And avoid the DTC altogether so that if the argument is not explicitly a NaN number, it will return false. Wherefore, testing against the following:

isNaNStatic(" x"); // will return false because it's still a string.

However: isNaNStatic(1/"x"); // will of course return true. as will for instance isNaNStatic(NaN); >> true.

But contrary to isNaN, the isNaNStatic("NaN"); >> false because it (the argument) is an ordinary string.

p.s.: The static version of isNaN can be very useful in modern coding scenarios. And it may very well be one of the main reasons I took my time for posting this.

Regards.

Pact answered 8/1, 2017 at 1:1 Comment(0)
B
0

isNAN(<argument>) is a function to tell whether given argument is illegal number. isNaN typecasts the arguments into Number type. If you want to check if argument is Numeric or not? Please use $.isNumeric() function in jQuery.

That is, isNaN(foo) is equivalent to isNaN(Number(foo)) It accepts any strings having all numerals as numbers for obvious reasons. For ex.

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true
Bywoods answered 12/4, 2017 at 6:32 Comment(0)
D
0

When checking if certain string value with whitespace or " "is isNaN maybe try to perform string validation, example :

// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

Doak answered 13/8, 2018 at 7:7 Comment(0)
E
0

I find it convenient to have a method specific to the Number class (since other functions that do conversions like parseInt have different outputs for some of these values) and use prototypal inheritance.

Object.assign(Number.prototype, {
  isNumericallyValid(num) {
    if (
      num === null
      || typeof num === 'boolean'
      || num === ''
      || Number.isNaN(Number(num))
    ) {
      return false;
    }
    return true;
  }
});
Erechtheum answered 1/9, 2020 at 2:20 Comment(0)
T
0

I use the following.

x=(isNaN(parseFloat(x)))? 0.00 : parseFloat(x);

Thrombosis answered 26/8, 2021 at 11:43 Comment(0)
D
-1

let isNotNumber = val => isNaN(val) || (val.trim && val.trim() === '');

console.log(isNotNumber(' '));
console.log(isNotNumber('1'));
console.log(isNotNumber('123x'));
console.log(isNotNumber('x123'));
console.log(isNotNumber('0'));
console.log(isNotNumber(3));
console.log(isNotNumber('    x'));
console.log(isNotNumber('1.23'));
console.log(isNotNumber('1.23.1.3'));

if(!isNotNumber(3)){
  console.log('This is a number');
}
Deform answered 13/7, 2021 at 12:53 Comment(1)
this doesn't answer the question and appears to be a vaguely random code snippet with no explanation provided.Coppery

© 2022 - 2024 — McMap. All rights reserved.