首页
/ core-js 的 ECMAScript Number 特性解析:二进制/八进制字面量解析与全套数字 API 的 Polyfill 实现

core-js 的 ECMAScript Number 特性解析:二进制/八进制字面量解析与全套数字 API 的 Polyfill 实现

2026-09-11 18:08:38作者:宣海椒Queenly

本篇技术指南以 core-js 仓库中的 ECMAScript: Number 特性文档 为主线,深入讲解 Number 构造函数对二进制(0b)与八进制(0o)字面量字符串的解析支持,并系统梳理 core-js 为 Number 提供的全部静态属性、静态方法、原型方法及全局 parseInt / parseFloat 的 Polyfill 模块、TypeScript 签名与推荐入口路径。读完本文,你将掌握如何在旧环境中补齐 Number 全系能力、理解 core-js 底层 ToNumber 抽象操作的实现细节,并能在实际项目中按需引入对应的 core-js 入口模块。

Number 构造函数对二进制与八进制字面量的支持

Number 构造函数是 core-js 在 ECMAScript 特性层面重点覆盖的对象之一,核心能力是支持将带 0b / 0o 前缀的二进制与八进制字面量字符串正确转换为十进制数值,例如文档给出的两个经典用例:

Number('0b1010101'); // => 85
Number('0o7654321'); // => 2054353

在较旧或存在兼容缺陷的 JavaScript 引擎中,Number(' 0o1')Number('0b1') 等调用可能返回 NaN 或结果错误。core-js 在 es.number.constructor.js 中通过如下判定决定是否强制替换原生构造函数:

var FORCED = isForced(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'));

即当引擎无法解析八进制/二进制前缀字符串,或错误地将带符号的十六进制 '+0x1' 解析成数值时,core-js 就以自研的 NumberWrapper 覆盖原生 Number

底层 ToNumber 抽象操作的实现

NumberWrapper 的核心逻辑是实现规范中的 ToNumber 抽象操作(ecma262/#sec-tonumber。其处理流程要点如下:

  1. 先做 ToPrimitive:通过 toPrimitive(value, 'number') 将传入值转为原始值;若原始值是 bigint 则直接返回,否则继续走 toNumber
  2. Symbol 抛错isSymbol(it) 时抛出 TypeError,即 Number(Symbol()) 是不被允许的;
  3. 字符串预处理:长度大于 2 的字符串先 trim 去除首尾空白;
  4. 带符号十六进制的兼容修复:当字符串以 +/- 开头且第三位是 x/X 时返回 NaN(例如 Number('+0x1') 应为 NaN,这是针对旧版 V8 的修复);
  5. 二进制 / 八进制快速路径:当首字符为 0 时,根据第二个字符分派——B/b 采用 radix = 2maxCode = 49O/o 采用 radix = 8maxCode = 55;随后逐字符校验剩余数字是否越界(越界返回 NaN),合法则 parseInt(digits, radix)
  6. 默认路径:以上均不命中时直接使用 +it 完成转换。

注意第 5 点与全局 parseInt 的差异:parseInt('0b12') 会解析出 0b1 并返回 1(解析到首个非法字符为止),而 ToNumber 要求 Number('0b12') 必须返回 NaN,core-js 的逐字符校验正是为了保证这一语义。

NumberWrapper 还正确处理了 new Number() 的包装语义:通过 calledWithNew 检测调用方式,配合 inheritIfRequirednew Number(...) 返回一个以 Number.prototype 为原型的包装对象,同时保证 1.constructor(foo) 这类边界情况不会误判为构造调用。

测试用例对解析行为的完整覆盖

单元测试文件 tests/unit-global/es.number.constructor.js 对该行为做了详尽验证:

  • 二进制用例QUnit.test('Number constructor: binary')):Number('0b1') → 1、Number('0B1') → 1,而 Number('0b12')Number('0b234')Number('0b1!')Number('+0b1')Number('-0b1') 全部为 NaN;同时验证首尾空白(含 WHITESPACES 全量空白字符)不影响解析;
  • 八进制用例QUnit.test('Number constructor: octal')):Number('0o7') → 7、Number('0O7') → 7,Number('0o18')Number('0o89a') 等非法串返回 NaN
  • 回归用例QUnit.test('Number constructor: regression')):覆盖十进制、十六进制('0x42' → 66)、对象 valueOf/toString 的优先级与仅调用一次、布尔值与 null 转换、Symbol 抛错、以及原生子类化(nativeSubclass(Number))等场景。

完整的 Number 内置 API 签名

关联文档给出了 core-js 所覆盖 Number 能力的完整 TypeScript 签名,这是判断"哪些 API 可放心使用"的直接依据:

class Number {
  constructor(value: any): number;
  toExponential(digits: number): string;
  toFixed(digits: number): string;
  toPrecision(precision: number): string;
  static isFinite(number: any): boolean;
  static isNaN(number: any): boolean;
  static isInteger(number: any): boolean;
  static isSafeInteger(number: any): boolean;
  static parseFloat(string: string): number;
  static parseInt(string: string, radix?: number = 10): number;
  static EPSILON: number;
  static MAX_SAFE_INTEGER: number;
  static MIN_SAFE_INTEGER: number;
}

function parseFloat(string: string): number;
function parseInt(string: string, radix?: number = 10): number;

可以看到 core-js 不仅 Polyfill 了 ES2015 引入的三个判断方法、两个解析方法与三个常量,还修复了 toExponential / toFixed / toPrecision 三个原型方法在旧引擎中的舍入缺陷,并把全局 parseFloat / parseInt 一并纳入修复范围。

各模块的源码实现要点

关联文档列出了 15 个独立模块,每个模块对应一个可独立引入的 Polyfill 单元。各模块的底层实现如下(均位于 packages/core-js/modules/):

模块 对应 API 实现要点
es.number.constructor.js Number 构造函数 自研 ToNumber,支持二进制/八进制解析,见上文
es.number.epsilon.js Number.EPSILON 定义为 Math.pow(2, -52),以 nonConfigurablenonWritable 方式挂载
es.number.is-finite.js Number.isFinite 复用 internals/number-is-finite.js,实现为 typeof it == 'number' && globalIsFinite(it)——只有真正的 number 类型才返回 true,与全局 isFinite 会做隐式类型转换的行为不同
es.number.is-nan.js Number.isNaN 实现为 number !== number,只有 NaN 自身不等于自身,不会像全局 isNaN 那样先把参数转成数字
es.number.is-integer.js Number.isInteger 复用 internals/is-integral-number
es.number.is-safe-integer.js Number.isSafeInteger 在整数判断基础上追加 abs(number) <= 0x1FFFFFFFFFFFFF(即 2^53 - 1)
es.number.parse-int.js Number.parseInt 复用 internals/number-parse-int,当原生实现与内部实现不一致时强制覆盖
es.number.parse-float.js Number.parseFloat 复用 internals/number-parse-float,逻辑同上
es.number.max-safe-integer.js Number.MAX_SAFE_INTEGER 常量 0x1FFFFFFFFFFFFF(即 9007199254740991)
es.number.min-safe-integer.js Number.MIN_SAFE_INTEGER 常量 -0x1FFFFFFFFFFFFF
es.number.to-exponential.js Number.prototype.toExponential 在引擎舍入行为异常(如 Edge 17-、IE11-、FF86- 等)时启用自研高精度舍入实现
es.number.to-fixed.js Number.prototype.toFixed 自研大数乘法/除法(multiply/divide 采用 1e7 分块),修复 (0.00008).toFixed(3) 等原生缺陷
es.number.to-precision.js Number.prototype.toPrecision 修复 toPrecision(1, undefined) 及 IE7- 的缺陷
es.parse-int.js 全局 parseInt 修复 parseInt(' 08') 与装箱 Symbol 等引擎缺陷(见 internals/number-parse-int 中的 FORCED 判定)
es.parse-float.js 全局 parseFloat 同样采用"仅在原生实现有缺陷时覆盖"的策略

关于 toFixedtoExponential 的精度修复

这两个原型方法是 core-js 修复的重点。es.number.to-fixed.js 通过 FORCED 判定检测原生实现是否存在已知缺陷,例如 (0.00008).toFixed(3) 是否等于 '0.000'(0.9).toFixed(0) 是否等于 '1'(1.255).toFixed(2) 是否等于 '1.25' 等;若存在缺陷则启用基于 1e7 分块的大数算法,并对 fractionDigits 超出 <a href="https://link.gitcode.com/i/6bb46adf927afee51224a15b43cc9834" target="_blank">0, 20] 的范围抛出 RangeError。[es.number.to-exponential.js 则针对 Edge 17-、IE11-、FF86- 等引擎的舍入问题(如 (-6.9e-11).toExponential(4)(12345).toExponential(3))提供自研实现,并避免 2 * x 溢出。

Entry Points:按需引入 Number 能力

core-js 支持粒度极细的按需引入。关联文档给出的 Number 相关入口路径如下:

core-js(-pure)/es|stable|actual|full/number
core-js(-pure)/es|stable|actual|full/number/constructor
core-js(-pure)/es|stable|actual|full/number/is-finite
core-js(-pure)/es|stable|actual|full/number/is-nan
core-js(-pure)/es|stable|actual|full/number/is-integer
core-js(-pure)/es|stable|actual|full/number/is-safe-integer
core-js(-pure)/es|stable|actual|full/number/parse-float
core-js(-pure)/es|stable|actual|full/number/parse-int
core-js(-pure)/es|stable|actual|full/number/epsilon
core-js(-pure)/es|stable|actual|full/number/max-safe-integer
core-js(-pure)/es|stable|actual|full/number/min-safe-integer
core-js(-pure)/es|stable|actual|full/number(/virtual)/to-exponential
core-js(-pure)/es|stable|actual|full/number(/virtual)/to-fixed
core-js(-pure)/es|stable|actual|full/number(/virtual)/to-precision
core-js(-pure)/es|stable|actual|full/parse-float
core-js(-pure)/es|stable|actual|full/parse-int

各命名空间含义与选择建议

根据 usage.md 的说明,入口路径中的 es|stable|actual|full 四个命名空间代表了不同的特性范围:

  • es:仅稳定的 ECMAScript 特性;
  • stable:稳定的 ES 特性加 Web 标准特性;
  • actual:全部"实际可用"特性(稳定 ES + Web 标准 + stage 3 提案),文档推荐优先使用 /actual/,因为它不含仍在实验中的早期提案;
  • full:全部特性,包括早期阶段提案。

Number 为例,实际使用时可以这样选择:

// 全局版本:直接引入即可打补丁
import "core-js/es/number";            // 仅稳定 ES 的 Number 特性
import "core-js/stable/number";        // 稳定 ES + Web 标准
import "core-js/actual/number";        // 推荐:稳定 + stage 3 提案
import "core-js/full/number";          // 全部(含早期提案)

// 只打补丁单个方法:
import "core-js/actual/number/is-finite";
import "core-js/stable/number/parse-int";
import "core-js/es/number/to-fixed";

pure 版本与 /virtual/ 入口

在不污染全局命名空间的 core-js-pure 版本中,原型方法无法直接挂到原生构造器上,因此 toExponentialtoFixedtoPrecision 这类原型方法提供了 /virtual/ 变体,配合绑定运算符(bind operator)以"虚拟方法"形式使用,例如(来自 usage.md 的用法):

import "core-js-pure/actual/number/virtual/to-fixed";
import "core-js-pure/actual/number/virtual/to-exponential";
import "core-js-pure/actual/number/virtual/to-precision";

需要注意,绑定运算符属于早期的 ECMAScript 提案语法,使用它存在一定风险;常规项目中更稳妥的做法是直接 import core-js-pure/es/number 等入口。仓库中 stable/number/index.js 等目录下的入口文件均是对 es 层级模块的简单转出(module.exports = parent),印证了命名空间之间的层级依赖关系:stableesactualstable 及 stage 3,fullactual 及早期提案。

实战注意事项与边界行为

综合源码实现与测试用例,使用 Number 相关 Polyfill 时应注意以下边界:

  1. 非法前缀返回 NaN 而非截断Number('0b12')Number('0o18') 返回 NaN,这是 ToNumberparseInt 语义的关键差异(parseInt('0b12') 会返回 1);
  2. 带符号十六进制是 NaNNumber('+0x1')Number('-0x1') 均为 NaN(旧版 V8 的兼容修复);
  3. 首尾空白被忽略' 0b1 ''\n 0o1\n ' 等带任意合法空白字符的字符串均可正常解析;
  4. Symbol 一律抛 TypeErrorNumber(symbol)new Number(symbol) 都会抛出异常;
  5. Number.EPSILON 等常量不可配置、不可写:core-js 以 nonConfigurable: true, nonWritable: true 方式定义,避免后续被篡改;
  6. toFixed/toExponential 的小数位参数范围fractionDigits 必须在 0 ~ 20 之间,否则抛出 RangeError
  7. 按需引入粒度:入口既可以精确到 number/is-finite 这样的单一方法,也可以按 /number 一次性引入整组;全局版本建议在应用入口顶部统一加载全部所需模块,以避免与其他库扩展原生对象时产生冲突。

总结

core-js 对 ECMAScript Number 特性的覆盖,既包括 Number('0b...') / Number('0o...') 这类二进制与八进制字面量解析能力(通过自研 ToNumber 抽象操作实现,并有 单元测试 全量验证),也包含 ES2015 以来的全部静态属性、静态方法与原型方法的 Polyfill 与缺陷修复。配合 es|stable|actual|full 四个命名空间与 core-js-pure/virtual/ 入口,开发者可以按需、无污染地补齐任意目标环境下的 Number 能力。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.81 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
945
1.86 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
537
607
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.28 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.39 K
1.48 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
401
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
347