75

I store some parameters client-side in HTML and then need to compare them as integers. Unfortunately I have come across a serious bug that I cannot explain. The bug seems to be that my JS reads parameters as strings rather than integers, causing my integer comparisons to fail.

I have generated a small example of the error, which I also can't explain. The following returns 'true' when run:

console.log("2" > "10")

1
  • This is really an instance of lexicographical string comparison: string comparison in javascript (read: the Why? of this question) Commented Feb 26, 2016 at 19:46

9 Answers 9

98

Parse the string into an integer using parseInt:

javascript:alert(parseInt("2", 10)>parseInt("10", 10))
Sign up to request clarification or add additional context in comments.

4 Comments

Fantastic. Is there also a way to check if the value is an int in the first place, simply so I can try to avoid more bugs at my end...
@Ronan: You can actually pass an int as the first argument to parseInt. parseInt turns its first argument into a string if it isn't already one, then parses it. If you really need to check if something is an int, though, you can usually use typeof 123 and check for a result of "number". This can have problems, however, if you pass in new Number(123), in which case it will return "object", but that isn't very common.
@Ronan: Oh, and you can check the constructor property, too, and compare that against Number. That seems to work in both cases.
If the param is a string that's a number then parseFloat(param) == param
33

Checking that strings are integers is separate to comparing if one is greater or lesser than another. You should always compare number with number and string with string as the algorithm for dealing with mixed types not easy to remember.

'00100' < '1' // true

as they are both strings so only the first zero of '00100' is compared to '1' and because it's charCode is lower, it evaluates as lower.

However:

'00100' < 1 // false

as the RHS is a number, the LHS is converted to number before the comparision.

A simple integer check is:

function isInt(n) {
  return /^[+-]?\d+$/.test(n);
}

It doesn't matter if n is a number or integer, it will be converted to a string before the test.

If you really care about performance, then:

var isInt = (function() {
  var re = /^[+-]?\d+$/;

  return function(n) {
    return re.test(n);
  }
}());

Noting that numbers like 1.0 will return false. If you want to count such numbers as integers too, then:

var isInt = (function() {
  var re = /^[+-]?\d+$/;
  var re2 = /\.0+$/;

  return function(n) {
    return re.test((''+ n).replace(re2,''));
  }
}());

Once that test is passed, converting to number for comparison can use a number of methods. I don't like parseInt() because it will truncate floats to make them look like ints, so all the following will be "equal":

parseInt(2.9) == parseInt('002',10) == parseInt('2wewe')

and so on.

Once numbers are tested as integers, you can use the unary + operator to convert them to numbers in the comparision:

if (isInt(a) && isInt(b)) {
  if (+a < +b) {
    // a and b are integers and a is less than b
  }
}

Other methods are:

Number(a); // liked by some because it's clear what is happening
a * 1      // Not really obvious but it works, I don't like it

1 Comment

The unary + operator is a lifesaver for quick homogenization - thanks for the tip.
31

Comparing Numbers to String Equivalents Without Using parseInt

console.log(Number('2') > Number('10'));
console.log( ('2'/1) > ('10'/1) );

var item = { id: 998 }, id = '998';
var isEqual = (item.id.toString() === id.toString());
isEqual;

4 Comments

this method is better no matter how big the number is :) thanks
Which is your preferred? .toString(), Number constructor, or arithmetical? Why?
This just works best. You don't need to cast anything + to make sure everything is save, check whether the value you want to compare is undefined / null (in case you did save an undefined/null value and comparing two undefined / null values).
I'd also add: using == is perfectly fine in my book. It's part of the language so why not use it (thoughtfully)? A good convention is to just add a comment next to it so others know it wasn't a mistake. Simply a "// ==" should suffice. Example: if (this.id == params.id) f(); // ==. That way other devs recognize that params.id is always or almost always going to be a string while this.id is always or almost always a number. Don't feel so guilty for leveraging different parts of the language.
8

+ operator will coerce the string to a number.

console.log( +"2" > +"10" )

1 Comment

Note: If a value is not a valid number you will get a NaN
7

Always remember when we compare two strings. the comparison happens on chacracter basis. so '2' > '12' is true because the comparison will happen as '2' > '1' and in alphabetical way '2' is always greater than '1' as unicode. SO it will comeout true. I hope this helps.

Comments

6

You can use Number() function also since it converts the object argument to a number that represents the object's value.

Eg: javascript:alert( Number("2") > Number("10"))

Comments

5

use parseInt and compare like below:

javascript:alert(parseInt("2")>parseInt("10"))

Comments

2

The answer is simple. Just divide string by 1. Examples:

"2" > "10"   - true

but

"2"/1 > "10"/1 - false

Also you can check if string value really is number:

!isNaN("1"/1) - true (number)
!isNaN("1a"/1) - false (string)
!isNaN("01"/1) - true (number)
!isNaN(" 1"/1) - true (number)
!isNaN(" 1abc"/1) - false (string)

But

!isNaN(""/1) - true (but string)

Solution

number !== "" && !isNaN(number/1)

Comments

1

The alert() wants to display a string, so it will interpret "2">"10" as a string.

Use the following:

var greater = parseInt("2") > parseInt("10");
alert("Is greater than? " + greater);

var less = parseInt("2") < parseInt("10");
alert("Is less than? " + less);

2 Comments

-1 What alert() wants is irrelevant! Yes it gets a boolean from the < result and coerces it to string, but by then it's too late to affect how the comparison worked. JS < operator behavior depends on its two arguments: if both are strings it does lexicographic comparison (so first character "2" is greater than "1"); if at least one was a number, it'd use numeric comparison. But your example is correct — parseInt() before comparison helps.
Number() or + or parseFloat are better if you want to support fractions e.g. parseInt('3.1') < parseInt('3.9') is false because both sides return 3. Note that parseInt('3foo!@#') and parseFloat('3foo!@#') both ignore trailing garbage and return 3, while Number('3foo!@#') and +'3foo!@#' return NaN.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.