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)
- 此代码演示了原始类型
number与Number包装对象之间的区别。通常应使用原始类型而不是包装对象。
特殊值:NaN、Infinity 及常量
Number 提供了特殊值(NaN、Infinity)和常量。
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的整数可能无法精确表示。如需精确性请考虑使用BigInt。EPSILON用于浮点数比较。
数字转换:Number()、parseInt、parseFloat 和 + 运算符
有多种方式可以将字符串转换为数字,其行为各异。
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,而parseInt和parseFloat会从字符串开头解析出可识别的数字部分。使用parseInt时,始终明确指定基数(radix)更为安全。
处理和检测 NaN:isNaN 和 Number.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这样的健壮实现,不仅比较绝对差值也考虑缩放。
整数与安全整数检测(isInteger、isSafeInteger)
有相关 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。
显示与格式化:toFixed、toPrecision、toString
有多种方法可以控制数字的显示方式。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.parseFloat、valueOf
Number.parseInt 和 Number.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.parseInt和Number.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.isNaN和Number.isFinite。 - 需要进行浮点数比较时,使用
Number.EPSILON或自定义比较函数。 - 整数需要保证精度时,使用
Number.isSafeInteger,超出安全范围时请选用BigInt。 - 你可以使用
toFixed或toPrecision进行显示用的四舍五入,但请注意返回值是字符串。
总结
Number 是 JavaScript 中所有数字(包括整数、小数、特殊值如 NaN、Infinity)的基本类型。需要注意类型转换与浮点误差,并正确使用如 Number.isNaN、Number.EPSILON 等方法。超出安全整数范围时请使用 BigInt,四舍五入或显示时用 toFixed 或 toPrecision。
您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。