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(非数字)有特殊性,即 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.parseInt / Number.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 时,请注意基数和输入字符串的空白处理。通常应避免使用包装对象。

参考:小工具示例 - 数值校验函数

下面是一些常用检测的小型工具函数。这有助于简化输入校验等任务。

 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