JavaScript 中的 `Number` 類別

JavaScript 中的 `Number` 類別

本文將解釋 JavaScript 中的 Number 類別。

我們將一步步詳細說明 Number 的特性、常見陷阱、實用 API 以及實際範例。

YouTube Video

JavaScript 中的 Number 類別

Number 是 JavaScript 的基礎數值型別,採用 IEEE-754 雙精度浮點數(64 位元)表示。

基礎:數值表示與型別檢查

在 JavaScript 中,所有數字都以原始的 number 型別表示。

 1// Primitive numbers and Number object
 2const a = 42;                 // primitive number
 3const b = 3.14;               // primitive float
 4const c = Number(10);         // primitive via constructor call (function form)
 5const d = new Number(10);     // Number object (wrapper)
 6
 7console.log(typeof a);        // "number"
 8console.log(typeof d);        // "object"
 9console.log(c == d);          // true  (value coerces)
10console.log(c === d);         // false (different types)
  • 此程式碼展示了原始型別 numberNumber 包裝物件之間的差異。通常建議使用原始型別,而非包裝物件。

特殊值:NaNInfinity 與常數

Number 提供了特殊值(NaNInfinity)及常數。

 1// Special numeric values and constants
 2console.log(Number.NaN);                 // NaN
 3console.log(Number.POSITIVE_INFINITY);   // Infinity
 4console.log(Number.NEGATIVE_INFINITY);   // -Infinity
 5
 6console.log(Number.MAX_VALUE);           // largest positive representable
 7console.log(Number.MIN_VALUE);           // smallest positive representable (closest to 0)
 8console.log(Number.MAX_SAFE_INTEGER);    // 9007199254740991
 9console.log(Number.MIN_SAFE_INTEGER);    // -9007199254740991
10console.log(Number.EPSILON);             // smallest difference ~2.220446049250313e-16
  • 大於或等於 MAX_SAFE_INTEGER 的整數可能無法精確表示,若需要精確度請考慮使用 BigIntEPSILON 用於浮點數比較。

數值轉換:Number()parseIntparseFloat+ 運算子

將字串轉換為數字有多種方法,每種方式行為略有不同。

 1// Converting strings to numbers
 2console.log(Number("42"));        // 42
 3console.log(Number("  3.14 "));   // 3.14
 4console.log(+ "7");               // 7 (unary +)
 5
 6console.log(parseInt("42px"));    // 42
 7console.log(parseFloat("3.14abc"));// 3.14
 8
 9// Careful with parseInt and radix
10console.log(parseInt("08"));      // 8
11console.log(parseInt("08", 10));  // 8 (explicit radix is safer)
  • Number() 除非整個字串為嚴格數值格式,否則會回傳 NaN,而 parseIntparseFloat 則會從字串開頭解析可讀的數字部分。使用 parseInt 時,建議務必明確指定基底(radix)。

處理與檢查 NaNisNaNNumber.isNaN

NaN(Not-A-Number)很特別,因為 NaN !== NaN。兩者的判定方式不同;全域的 isNaN 會執行型別轉換,可能產生誤判,因此推薦使用 Number.isNaN

1// NaN detection differences
2console.log(NaN === NaN);             // false
3
4console.log(isNaN("foo"));            // true  -> because "foo" coerces to NaN
5console.log(Number.isNaN("foo"));     // false -> "foo" is not the numeric NaN
6
7console.log(Number.isNaN(NaN));       // true
  • 檢查數值與驗算結果時請用 Number.isNaN,以避免不必要的型別轉換。

浮點誤差及使用 Number.EPSILON 進行比較

因為 IEEE-754 規格會產生如 0.1 + 0.2 !== 0.3 這類誤差。嚴格比較時,通常會透過差值與 Number.EPSILON 來判斷。

1// Floating point precision example and EPSILON comparison
2const sum = 0.1 + 0.2;
3console.log(sum === 0.3);             // false
4
5function nearlyEqual(a, b, epsilon = Number.EPSILON) {
6  return Math.abs(a - b) <= epsilon * Math.max(1, Math.abs(a), Math.abs(b));
7}
8
9console.log(nearlyEqual(sum, 0.3));   // true
  • 若允許有誤差比較,建議實作如 nearlyEqual 這類同時考慮比例與絕對差的健壯函式。

檢查整數與安全整數(isIntegerisSafeInteger

有 API 可以檢查某值是否為整數,以及是否落於安全整數範圍內。

1// Integer and safe integer checks
2console.log(Number.isInteger(3));                 // true
3console.log(Number.isInteger(3.0));               // true
4console.log(Number.isInteger(3.1));               // false
5
6console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
7console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
  • 當需要大整數的精確性時,請使用 Number.isSafeInteger 檢查,並針對超過範圍的數字考慮使用 BigInt

顯示與格式化:toFixedtoPrecisiontoString

有方法可以控制數值的顯示格式。toFixed 會返回指定位數的小數字串,但要留意四捨五入的處理。

1// Formatting numbers for display
2const x = 1.23456;
3console.log(x.toFixed(2));         // "1.23"   (string)
4console.log(x.toPrecision(3));     // "1.23"   (string with total significant digits)
5console.log((255).toString(16));   // "ff"     (hexadecimal string)
  • toFixed 回傳的是字串,因此進行運算時要注意數值轉換後的結果。

關於字串連接與 + 運算子的注意事項

+ 運算子同時用於數字加法和字串連接,依據型別可能產生非預期結果。

1// Pitfall with + operator and type coercion
2console.log(1 + 2 + "px");    // "3px"
3console.log("px" + 1 + 2);    // "px12"
4console.log(1 + "2" - 0);     // 3  (string coerced to number for subtraction)
  • 字串和數字混用時,建議明確使用 String()Number() 或樣板字面值來避免隱式型別轉換。

進階用法:Number.parseIntNumber.parseFloatvalueOf

Number.parseIntNumber.parseFloat 是全域函式的別名。valueOf 用來取得 Number 物件的原始值,但實務上很少需要。

1// Number.parseInt/parseFloat aliases and valueOf example
2console.log(Number.parseInt("100", 10));   // 100
3console.log(Number.parseFloat("3.14"));    // 3.14
4
5const nObj = new Number(5);
6console.log(nObj.valueOf());               // 5
7console.log(nObj + 1);                     // 6  (object coerced to primitive)
  • 使用 Number.parseIntNumber.parseFloat 時要留意基底(radix)與輸入字串的修剪。通常應避免使用包裝物件。

參考:簡易工具範例-數值驗證函式

這裡提供集結常用檢查的小型實用函式。這能讓輸入驗證等作業變得更簡單。

 1// Small number utility functions
 2function toNumberStrict(value) {
 3  // Return a Number or throw for invalid numeric strings
 4  const n = Number(value);
 5  if (typeof value === "string" && value.trim() === "") {
 6    throw new Error("Empty string is not a valid number");
 7  }
 8  if (Number.isNaN(n)) {
 9    throw new Error(`Invalid number: ${value}`);
10  }
11  return n;
12}
13
14function almostEqual(a, b, eps = Number.EPSILON) {
15  // Robust relative comparison
16  return Math.abs(a - b) <= eps * Math.max(1, Math.abs(a), Math.abs(b));
17}
  • 這些都是可重複用於輸入處理及比較的高通用性函式。拋出錯誤的實作對於驗證用途來說非常有用。

效能與最佳實踐總結

使用 Number 時,請留意以下實務重點。

  • 基本上,請直接使用原始型別 number,避免使用 new Number()
  • 字串轉數值時,視需求選擇 Number()(嚴格)或 parseInt/parseFloat(部分擷取)。
  • 請以 Number.isNaNNumber.isFinite 進行安全判斷。
  • 浮點數比較請用 Number.EPSILON 或自行建立比較函式。
  • 需要整數精確度時,請用 Number.isSafeInteger 檢查,超出範圍時採用 BigInt
  • 你可以使用 toFixedtoPrecision 來進行顯示用的四捨五入,但請注意回傳值是字串。

總結

Number 是 JavaScript 中所有數字的基礎類型,包括整數、小數及特殊值(NaNInfinity)。必須注意型別轉換與浮點誤差,並正確使用 Number.isNaNNumber.EPSILON 等方法。超過安全整數範圍時請用 BigInt,進行四捨五入與顯示時則使用 toFixedtoPrecision

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video