Post

[Forwarded] A 10-line “Is this a number?” check: how is-number works | [轉] 10 行搞掂「係咪數字」:拆解 is-number 點樣判斷

[Forwarded] A 10-line “Is this a number?” check: how is-number works | [轉] 10 行搞掂「係咪數字」:拆解 is-number 點樣判斷

When you validate user input, you’ll see values like "42", " 3.14 ", or "1e3".
typeof x === 'number' misses numeric strings, while isNaN(x) can be tricked by coercion.

The is-number utility returns true only when the value is either a finite JavaScript number or a non-empty string that can be converted to a finite number.

The code

1
2
3
4
5
6
7
8
9
10
11
module.exports = function(num) {
  if (typeof num === 'number') {
    return num - num === 0;
  }

  if (typeof num === 'string' && num.trim() !== '') {
    return Number.isFinite ? Number.isFinite(+num) : isFinite(+num);
  }
  
  return false;
};

1) Why num - num === 0?

For finite numbers, n - n is always 0.

But for NaN, and for Infinity - Infinity, the result is NaN—so the comparison fails. This effectively filters out NaN and ±Infinity.

2) Why trim() !== ''?

Without it, +'' and +' ' become 0, which would incorrectly treat blank input as numeric. The trim() guard prevents that.

3) Why +num?

Unary + explicitly converts the operand to a number (similar intent to Number(num)), so strings like " 5 ", "1e3", or even "0x11" can become numbers.

4) Number.isFinite vs global isFinite

  • Number.isFinite(x) checks “is x a finite number” without coercion.
  • Global isFinite(x) coerces first, which can be surprising.

The fallback exists for older runtimes; +num ensures both paths test the numeric conversion consistently.


做表單/API 入參驗證,你成日會見到:"42"" 3.14 ""1e3",甚至 " "

淨係用 typeof x === 'number' 會漏咗字串數字;用 isNaN(x) 又好易畀型別轉換整蠱。

is-number 呢段做法就係:只要係「有限嘅 number」或者「可轉成有限 number、而且唔係空白嘅字串」先回傳 true

原始碼

1
2
3
4
5
6
7
8
9
10
11
module.exports = function(num) {
  if (typeof num === 'number') {
    return num - num === 0;
  }

  if (typeof num === 'string' && num.trim() !== '') {
    return Number.isFinite ? Number.isFinite(+num) : isFinite(+num);
  }
  
  return false;
};

1)點解用 num - num === 0

正常有限數:n - n 一定係 0

NaN - NaN 仍然係 NaNInfinity - Infinity 都會變 NaN,所以唔會等於 0——即係自動篩走 NaN 同 ±Infinity

2)字串分支:trim() 防止「空白當 0」

如果冇 num.trim() !== ''+''+' ' 都會變 0,咁你輸入空白都會被當成數字。trim() 就係專登擋住呢啲情況。

3)+num 一元加號:顯式轉做數字

一元 + 會嘗試將操作數轉成 number,所以 " 5 ""1e3"、甚至 "0x11" 都可能轉到數。

所以呢個實作會接受十六進制字串(例如 “0x11”)——佢冇限制「只准十進制」。

4)Number.isFinite 同全域 isFinite 有咩分別?

  • Number.isFinite(x):唔做隱式轉型,直接判斷係咪有限 number。
  • 全域 isFinite(x):會先轉型再判斷,可能有驚喜(亦可能有驚嚇)。

作者寫兼容分支,係為咗舊環境冇 Number.isFinite 都用得;而 +num 令兩邊都先做同一種數值轉換

This post is licensed under CC BY 4.0 by the author.