How to check if a value is a number

JavaScript polyfill, by , Monday, March 17th, 2014

There are different approaches to getting to the answer to this question regardless of what you mean by checking if a value is a number. If you are trying to determine if a value is numeric, meaning that it can be parsed to a numeric value, then you can use the following function;

  1. var isNumeric = function (n) {
  2. return !isNaN(parseFloat(n)) && isFinite(n);
  3. };

This will return true for both strings consisting of only of numbers and actual finite numbers, which is great if that is sufficient for your task. But if you need more precision, and only can accept actual number values, you can use the following function;

  1. var isNumber = function (n) {
  2. return isFinite(n) && +n === n;
  3. };

This function (isNumber) will only return true, if the value is an actual finite number. These two examples should cover your needs when it comes to checking if a value is a number or numeric, but how do they work and are these the only ways to make this test? Why can we just use isNaN? And why do we need isFinite? To answer this, lets look at what the specifications says about these methods.

Why not just use isNaN?

First of, you might be tempted to pose the question; why we do not just use the build in isNaN() method to do the check? The reason for this, is that the isNaN() method works as follows: (The definitions are from the ECMAScript-262 standard section 15.1.2.4)

  1. If ToNumber(number) is NaN, return true.
  2. Otherwise, return false

Here the ToNumber operation corresponds to doing conversion with the + (plus) operator, which we can try in the browser console, on a few carefully selected values;

>+'Durian';
 NaN
>+' ';
 0
>+Infinity
 Infinity
>+null
 0
>+true
 1

This illustrates the problem with isNaN in that even though the string 'Durian' correctly returns NaN the empty string ' ' returns 0, and even more surprisingly +null returns 0! This is bad if you really need to be sure that the given value is in fact a number. Furthermore we see that +Infinity returns Infinity which some might argue is correct, but which no matter how you look at it, does not help in our situation. Rather the opposite.

Trying to fixt isNaN with parseFloat

At this point we see that most of our problems stem from values being wrongly converted to numerical values, so to deal with this why not take advantage of the build in method parseFloat, which works something along the lines of; (this is not a complete of the steps of workings for the parseFloat method. However, you can find the full list in the ECMAScript-262 documentation section 15.1.2.3)

  1. Let inputString be ToString(string).
  2. Let trimmedString be a substring of inputString... (no leading white spaces)
  3. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral, return NaN.
  4. ...

All we need to get from the steps that define how the method works is, that the trimmed string needs to satisfy the syntax of a StrDecimalLiteral, which essentially means that what is left after trimming away leading white spaces can, when converted to a number represent an actual number. It is obvious from this, that if we apply these rules to the before tested values the +' ', +null, and +true expressions will now return NaN. What is less obvious is, that +Infinity still will pass as a number, which is technically correct, but practically not very convenient. Another problem occurs when we realize, that parseFloat works from left to right, which means that, "d3" will return NaN while "3d" will return 3! This is no good as neither the string "3d" or "d3" are numerical.

Coincidentally fixing the problem with isFinite

This is a situation where an obvious idea would be to turn to the build in method isFinite for help. At least we expect it to get rid of the problem of Infinity parsing as a number, so lets look at how it works; (again this definition is taken from the ECMAScript-262 standard)

  1. If ToNumber(number) is NaN, +∞ or -∞, return false.
  2. Otherwise, return true.

If we apply these conditions to the above, we see that it helps us get rid of the problem with Infinity, as the specifications says that the isFinite method will return false if it encounters an infinite number. The question that now remains is; does it help us with the "3d"/"d3" problem? If you remember from talking about the isNaN, the ToNumber method is equivalent to applying the + operator to the string, and if we try that in the console, we see, that both +"3d" and +"d3" return NaN. This is the argument for why the very first mentioned isNumeric function works, but now knowing why it works poses a new question.

Do we really need isNaN?

Looking at the specifications above, it is obvious that the isNaN and isFinite methods work in very similar ways. The isFinite method is just a negation of isNaN with the added condition that it also checks for infinity. This of course means, that you can write the isNumeric function replacing !isNaN with isFinite and it will behave exactly the same, so technically we do not need isNaN except maybe for readability.

If you look through the ECMAScript specifications you will find, that you can write the isNumberic function in yet another way, but it involves an controversial part of the JavaScript language; the double equal (==) comparison operator.

  1. var isNumeric = function (n) {
  2. return isFinite(n) && parseFloat(n) == n;
  3. };

If we look at how the double equal comparison operator works in our situation, which is equating using The Abstract Equality Comparison Algorithm, we find at step 4 and 5; (this is taken from the ECMAScript-262 standard section 11.9.3)

  1. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
  2. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

What this means in our context is, that since anything parsed to the parseFloat() method either returns a number or NaN the result will only be a comparison between either NaN and some other value, which will always return false, or it will be between a number and some other value, which will return true if ToNumber of that value is a number. With this said, using the double equal comparison operator is discouraged, as its logic of conversion is not easy to remember. If you instead use the triple equal (===) comparison operator you will get the same functionality as in the isNumber function. However we can not just remove an equal from the isNumber method and expect it to behave in the same way as the isNumeric method as, because we do no longer do strict comparison, we need to guard our self from situations like an empty string, which prefixed by + returns 0 and therefore would pass as being numeric. So when it comes to numbers in JavaScript we have to step carefully.