-1

I've seen people using regex, typeof or some built-in function like isNaN; to check if a variable / object's property is number or not.

But then today I found a "hack":

if(a.x*1) {
    //a.x if a number
} else {
    //a.x is not a number; a.x*1 is NaN
}

I'm just wondering if there is any downside to this trick.

Edit: I can't control the value of a.x, but I know it's either a number (1.2), a string("error") or a string that can be coerced to a number ("1.2"). I need a fast and clean way to both check its validity and convert it into a number.

Edit2: What if I check with a.x*1!==NaN?

Demintika
  • 1
  • 1
  • 7
    Not trustworthy, what if the `x` property is the number 0, or a numeric string that gets coerced to a number? Use something like `isFinite` instead – CertainPerformance Oct 02 '18 at 07:30
  • 1
    So...it's another implicit conversion. It's essentially the same as as doing `+a.x` but it's longer and less idiomatic. It has the same benefits and drawbacks. The `if` check itself is the thing that's wrong, though since you're testing if the *output* is truthy. if you want to check if something is a number, surely you want to check...if it's a number, not if some operation results in a falsey value. – VLAZ Oct 02 '18 at 07:33
  • Might be helpful https://stackoverflow.com/a/1303650/1918287 – Maor Refaeli Oct 02 '18 at 07:34
  • After the edits - why do you want to come up with a new way to check if it's a number instead of using established ones? – VLAZ Oct 02 '18 at 07:48
  • @vlaz Because copying a regex all over the place is not fast nor clean. I'm just asking if `*1` is a valid way to check, so I can use it in the future depending on situation. – Demintika Oct 02 '18 at 08:08
  • Make a function and call it `isNumeric`, then call it. Done, you're not copying regex or anything all over the place now. You can even use a library to do that and if you have something like Underscore or Lodash in your project, you already have that functionality available. So, you've never been forced to copy/paste code. – VLAZ Oct 02 '18 at 08:15

2 Answers2

3

Your check will incorrectly claim 0 isn't a number, so no, it isn't a replacement for isNaN or similar.

Note that if you want to know if a.x is already a number (and not something that can be coerced to a number), even isNaN isn't the right tool, since it will report that "12" is a number, or that any date instance is. To check if it's already a number (rather than something that can be coerced to one), you need typeof. (Of course, typeof NaN is "number", so you have to allow for that, too.)

So if you want to know if a.x is already a number and isn't NaN:

if (typeof a.x === "number" && !isNaN(a.x))

If you want to know if it's a number or something that can be implicitly coerced to a number that isn't NaN:

if (!isNaN(a.x))
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I need the latter, but `isNaN` return false with empty string and string with only spaces, which can happen in my code. – Demintika Oct 02 '18 at 07:50
  • @Demintika - Yup. Implicit conversion converts empty strings or strings containing only whitespace to `0`, which is whacky and arguably wrong, but there it is. If you don't want that, you need a more thorough check. For instance: `if (!isNaN(a.x) && (typeof a.x !== "string" || a.x.trim()))` – T.J. Crowder Oct 02 '18 at 07:59
  • Well, that's longer than I would consider "fast and clean". Thanks for the help anyway. – Demintika Oct 02 '18 at 08:22
0

Multiplying someVariable by 1 will cause implicit conversion to a number. This is the same as doing someVariable - 0 or +someVariable or the explicit Number(someVariable).

One downside to using the proposed method is that using a unary plus (+) or calling Number as a version for the conversion is idiomatic in JavaScript, which means it's well understood, so using another method to achieve the same can be confusing and make your code harder to read.

However, there is another aspect - the result of all of those conversions would not accurately tell you if the value was a number or not. Consider the following:

function isNumber(someVariable) {
  if(someVariable*1) {
    console.log(`"${someVariable}" is a number. For real: ${typeof someVariable}`)
  } else {
    console.log(`"${someVariable}" is not a number. It was a ${typeof someVariable}`)
  }
}

//these are correct
isNumber(1);
isNumber("abc");

//these are incorrect
isNumber(0);
isNumber("123");
isNumber("   321");
isNumber([1]); //logged as simply *1* the string value of an array with with one element is that element

var obj = {
  name: "Fred",
  age: 42,
  valueOf: function() {
    return this.age;
  }
}

//this is also incorrect
isNumber(obj)

Checking the result of some operation would, by definition, tell you about the result of that operation. So, checking if something can be implicitly converted to a number by examining the result would tell you exactly that - the source could be implicitly converted to a number.

Furthermore, when doing if (resultOfImplicitConversion) you are checking if that result is truthy or falsy. That's not the same as checking it's type.

So, the pitfalls of your proposed method is that it is inaccurate in both steps of its attempted verification, and it also possibly inaccurately presents your intentions to future readers of your code (including yourself).

If you want to check if a value is a number, then follow this great answer on Stack Overflow

VLAZ
  • 26,331
  • 9
  • 49
  • 67