8
\$\begingroup\$

Sometimes, there's the need to verify if a given number is an integer or a decimal. Since JavaScript doesn't distinguish between both, I've made an extremelly basic function.

function isInteger(num){
    var numCopy = parseFloat(num);
    return !isNaN(numCopy) && numCopy == numCopy.toFixed();
}

As you can see, it relies on checking if the number without decimals is the same as the parsed value. I'm not so confident about this.

Notice that this may return true for some scientific notation values.

Examples of results:

  • 1.0: true (JavaScript treats <n>.0 as an integer)
  • 1e3: true
  • 1.2345e2: false (equivalent to 123.45)
  • 1.2345e5: true (equivalent to 123450)
  • 1e200: true (equivalent to Infinity)

Is there any more reliable way of checking? The results seem to be consistent with the expected results. Regular expressions are an option but they are clunky.

\$\endgroup\$
  • 1
    \$\begingroup\$ Have you checked out the polyfill or ES6's isInteger function? Check it here: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - I think this is agreeably the best way to find out, but as always, be aware of JS rounding stuff for you. \$\endgroup\$ – somethinghere Aug 21 '15 at 9:53
  • \$\begingroup\$ @somethinghere That's a really great suggestion! Put it in the form of an answer and I'll upvote it for sure \$\endgroup\$ – Ismael Miguel Aug 21 '15 at 9:56
  • \$\begingroup\$ @Downvoter Care to explain? \$\endgroup\$ – Ismael Miguel Sep 3 '15 at 21:46
5
\$\begingroup\$

In ES6, the next version of Javascript, there will be a function exactly for this purpose called Number.isInteger(). Currently, MDN offers the following polyfill which I assume therefore does the best Javascript can to determine whether something is an integer. There are edge cases of course, but for most everyday use it will do the trick:

Number.isInteger = Number.isInteger || function(value) {
    return typeof value === "number" && 
           isFinite(value) && 
           Math.floor(value) === value;
};

I think this is the best we will do in the meanwhile, as passing string to a number function is an effective way of doing it, but calling toString on a number makes it go through conversion as well, resulting in potential issues.

There are already a couple of browsers that support it like Chrome and Firefox, but the big one (Safari) doesn't yet and neither does IE/Edge, so the polyfill will have to do. For more info, see MDN's writeup, it's quite insightful:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger#Browser_compatibility

Note: Polyfills like this are useful, but there are some concerns about amending these core features of JS. As I say in the comments, as long as you implement something that doesn't exist or replace anything, I think it's alright. Use in moderation.

You can always wrap it in it's own function and call it as a global function if you prefer not to use this polyfill.

\$\endgroup\$
  • \$\begingroup\$ I would just add a line saying that messing with prototypes is a bad practice, and that this can be used as a simple named function. Other than that, +10 for you! \$\endgroup\$ – Ismael Miguel Aug 21 '15 at 10:45
  • \$\begingroup\$ @IsmaelMiguel I have heard a lot about it being bad to mess with prototypes in this way, but nobody ever explained me why. I understand rewriting a method from, say, Number is dangerous because it gives unexpected results, but adding a method seems perfectly harmless to me. Do you have got any good references on why prototype amending is bad? I'd love to read about that. \$\endgroup\$ – somethinghere Aug 21 '15 at 10:48
  • \$\begingroup\$ At the moment, I don't recall any article to read. But imagine that your code relies on some polyfill, that is set to the prototype. If anyone changes the prototype by, for example, doing window.Number = window.String, your whole code is broken. Besides, messing with prototypes may crash with other codes that rely on a specific prototype method to return a non-standard value or has a different behaviour. \$\endgroup\$ – Ismael Miguel Aug 21 '15 at 10:59
  • \$\begingroup\$ Yeah that's kind of what I meant though, you don't mess with prototypes themselves, but I think appending a method is perfectly fine as long as it does not replace an already existing method. It might be best to have an ES6 check first (if(!Number.isInteger)), but otherwise I really think this particular thing is harmless. Replacing Number with Int etc... Thats obviously bad :) \$\endgroup\$ – somethinghere Aug 21 '15 at 11:01
  • 1
    \$\begingroup\$ I concur, so I have added it to my answer. \$\endgroup\$ – somethinghere Aug 21 '15 at 11:04
4
\$\begingroup\$

The question is a little vague, but right away I tried to break it and was successful with this

function isInteger(num){
    var numCopy = parseFloat(num);
    return !isNaN(numCopy) && numCopy == numCopy.toFixed();
}
isInteger(.9999999999999999999998/.9999999999999999999999);
true

probably because of loss of precision, as @Gallant noted the decimals are getting rounded to zero

Depending on what you are doing this is probably sufficiently accurate.

\$\endgroup\$
  • \$\begingroup\$ This is more accurately due to loss of precision from floating point values; both decimals are getting rounded to 1 before the division occurs. isInteger(.9999999999999999999998) would also return true because of this. \$\endgroup\$ – Gallant Aug 20 '15 at 21:43
  • \$\begingroup\$ @Gallant, you are totally right. \$\endgroup\$ – Malachi Aug 20 '15 at 21:48
  • \$\begingroup\$ If you have a look at the ES6 polyfill of isInteger (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) you will see this also fails this test. Javascript simply cannot compute these properties without converting them, so they will also wind up being 1. \$\endgroup\$ – somethinghere Aug 21 '15 at 9:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.