5

I'm simply trying to evaluate if an input is a number, and figured isNaN would be the best way to go. However, this causes unreliable results. For instance, using the following method:

function isNumerical(value) {
    var isNum = !isNaN(value);
    return isNum ? "<mark>numerical</mark>" : "not numerical";
}

on these values:

isNumerical(123));     // => numerical
isNumerical("123"));   // => numerical
isNumerical(null));    // => numerical
isNumerical(false));   // => numerical
isNumerical(true));    // => numerical
isNumerical());        // => not numerical

shown in this fiddle: http://jsfiddle.net/4nm7r/1

Why doesn't isNaN always work for me?

Ky -
  • 30,724
  • 51
  • 192
  • 308
  • 2
    The logic of your return statement is backwards. Also, things can be non-numerical without being `NaN`. – Ted Hopp Jun 13 '13 at 19:21
  • @TedHopp Thanks! My question stands, though – Ky - Jun 13 '13 at 19:28
  • my question is more about what the source of the ambiguity is, rather than how to make my function work – Ky - Jun 13 '13 at 21:54
  • The ambiguity, I think, is that when coerced to a numeric value (say, by using the unary `+` operator), `+null` becomes 0 but `+undefined` becomes `NaN`. The latter corresponds to your last case. – Ted Hopp Jun 13 '13 at 22:21

4 Answers4

5

isNaN returns true if the value passed is not a number(NaN)(or if it cannot be converted to a number, so, null, true and false will be converted to 0), otherwise it returns false. In your case, you have to remove the ! before the function call!

It is very easy to understand the behaviour of your script. isNaN simply checks if a value can be converted to an int. To do this, you have just to multiply or divide it by 1, or subtract or add 0. In your case, if you do, inside your function, alert(value * 1); you will see that all those passed values will be replaced by a number(0, 1, 123) except for undefined, whose numerical value is NaN.

You can't compare any value to NaN because it will never return false(even NaN === NaN), I think that's because NaN is dynamically generated... But I'm not sure.

Anyway you can fix your code by simply doing this:

function isNumerical(value) {
    var isNum = !isNaN(value / 1); //this will force the conversion to NaN or a number
    return isNum ? "<mark>numerical</mark>" : "not numerical";
}
Niccolò Campolungo
  • 11,824
  • 4
  • 32
  • 39
  • Good point, and I've modified my post slightly. However, I still would like a reliable way to discover if `value` is numerical – Ky - Jun 13 '13 at 19:28
  • @Supuhstar Please define "numerical". Should it include true, false, null and undefined? Should strings like "100$" be considered numerical? – bfavaretto Jun 13 '13 at 19:29
  • I'm going to use this to parse a cookie. To do this, I need to find out if the stored value was a boolean, number, or text, and I try to avoid string parsing if at all possible – Ky - Jun 13 '13 at 19:32
  • 1
    Try `isNaN(parseFloat(value))` @Supuhstar – bfavaretto Jun 13 '13 at 19:33
  • @LightStyle http://jsfiddle.net/4nm7r/3/ your method doesn't work >.> – Ky - Jun 13 '13 at 19:51
  • @bfavaretto http://jsfiddle.net/4nm7r/4/ works great! Why not submit as an answer? – Ky - Jun 13 '13 at 19:52
  • I have edited it another(I think the last) time. – Niccolò Campolungo Jun 13 '13 at 20:04
  • @LightStyle http://jsfiddle.net/4nm7r/5/ still doesn't work :/ – Ky - Jun 13 '13 at 20:57
  • @Supuhstar remove the other `isNaN` function, leave the default one – Niccolò Campolungo Jun 13 '13 at 20:58
  • @LightStyle http://jsfiddle.net/4nm7r/8/ still has promblembs – Ky - Jun 13 '13 at 21:18
  • 1
    No, it doesn't have problems, it is different from what you expected from it. That's because you wanted something that is not what `isNaN` does, so the code seems not working to you. If you want a different implementation, I think that there are some answers that are exactly what you're looking for. Anyway, mine was just a clarification, because you had not totally clear how `isNaN` works. Greetings! – Niccolò Campolungo Jun 13 '13 at 21:22
1

Your ternary statement is backward, if !isNaN() returns true you want to say "numerical"

return isNum ? "not numerical" : "<mark>numerical</mark>";

should be:

return isNum ? "<mark>numerical</mark>" : "not numerical";

See updated fiddle:

http://jsfiddle.net/4nm7r/1/

Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
1

Now that you already fixed the reversed logic pointed out on other answers, use parseFloat to get rid of the false positives for true, false and null:

var isNum = !isNaN(parseFloat(value));

Just keep in mind the following kinds of outputs from parseFloat:

parseFloat("200$"); // 200
parseFloat("200,100"); // 200
parseFloat("200 foo"); // 200
parseFloat("$200"); // NaN

(i.e, if the string starts with a number, parseFloat will extract the first numeric part it can find)

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
1

I suggest you use additional checks:

function isNumerical(value) {
    var isNum = !isNaN(value) && value !== null && value !== undefined;
    return isNum ? "<mark>numerical</mark>" : "not numerical";
}

If you would like treat strings like 123 like not numerical than you should add one more check:

var isNum = !isNaN(value) && value !== null && value !== undefined && (typeof value === 'number');
Dmitry
  • 101
  • 3