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

Viewed 82015

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.

25 Answers

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.

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 :)

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

Try using:

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

Or

alert(isNaN(parseFloat("    ")));

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

alert(' ' * 1); // 0
alert('x' * 1); // NaN

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);
}

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.

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.

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

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 }

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;
  }
});

I use the following.

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

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');
}

Related