core-js 中 Iterator.range 的完整指南:TC39 提案实现、入口与用法详解
core-js 中 Iterator.range 的完整指南TC39 提案实现、入口与用法详解【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js导读Iterator.range是 TC39 迭代器 range 提案proposal-iterator.range提出的静态方法用于创建一个按固定步长、可从起点遍历到终点的数值范围迭代器。在 core-js 仓库中该功能以esnext.iterator.range模块实现同时保留了旧版Number.range/BigInt.range的兼容入口。本文将基于 官方功能文档 与仓库源码完整讲解其类型签名、三种调用形式、step与inclusive参数的精确语义、异常处理边界、Entry points 以及底层NumericRangeIterator的实现原理读完即可在项目里准确使用并排查问题。功能概述与提案背景Iterator.range的目标是提供一种与 Python 的range()类似的、惰性求值的数值区间迭代能力。与Array.from({ length: n }, (_, i) start i)或手写 for 循环不同它返回的是一个实现了迭代器协议的NumericRangeIterator值在每次调用next()时才计算因而可以支持超长区间而不预先占用内存。提案规范TC39 proposal-iterator.rangehttps://tc39.es/proposal-iterator.range/提案仓库tc39/proposal-Number.rangehttps://github.com/tc39/proposal-Number.range/core-js 模块esnext.iterator.range在 core-js 内部该功能与早先的Number.range、BigInt.range提案共享同一套实现后两者被标记为“将在 core-js4 移除的旧方法”见 esnext.number.range.js 与 esnext.bigint.range.js 中的TODO: Remove from core-js4注释因此本文会同时说明它们的兼容用法。类型签名与调用形式官方文档给出的 Built-ins signatures 如下class Iterator { range(start: number, end: number, options: { step: number 1, inclusive: boolean false } | step: number 1): NumericRangeIterator; range(start: bigint, end: bigint | Infinity | -Infinity, options: { step: bigint 1n, inclusive: boolean false } | step: bigint 1n): NumericRangeIterator; }可以看到存在两条重载分别面向number和bigint两种数值类型。结合 esnext.iterator.range.js 的入口实现range: function range(start, end, option) { if (typeof start number) return new NumericRangeIterator(start, end, option, number, 0, 1); if (typeof start bigint) return new NumericRangeIterator(start, end, option, bigint, BigInt(0), BigInt(1)); throw new $TypeError(Incorrect Iterator.range arguments); }可以归纳出以下三条调用规则两个参数形式Iterator.range(start, end)此时step默认为 1递减区间则为 -1inclusive默认为false对象 options 形式Iterator.range(start, end, { step, inclusive })可分别指定步长与是否包含终点数字步长简写形式Iterator.range(start, end, step)第三个参数直接传数值或 BigInt 作为步长。第三个参数option的具体解析逻辑在 numeric-range-iterator.js 中option为null或undefined使用默认步长与默认inclusive falseoption是对象读取option.step与option.inclusiveoption与start同类型number 或 bigint视为步长简写其他情况抛出TypeError(Incorrect Iterator.range arguments)。需要特别说明的是该接口并不做隐式类型转换传入字符串1、普通对象或带valueOf的对象都会直接抛错见下方异常边界一节这与许多习惯做隐式转换的 API 不同。核心示例解读官方文档提供了两个示例这里逐一拆解其输出逻辑for (const i of Iterator.range(1, 10)) { console.log(i); // 1, 2, 3, 4, 5, 6, 7, 8, 9 }默认区间为左闭右开从 1 开始步长 1终点 10 本身不会被产出因此输出 1 到 9 共 9 个值。for (const i of Iterator.range(1, 10, { step: 3, inclusive: true }) { console.log(i); // 1, 4, 7, 10 }步长改为 3且inclusive: true表示包含终点1、134、437、7310恰好命中终点 10 并输出。若inclusive为false则 10 不会被输出序列为 1、4、7。更多边界示例来自仓库测试tests/unit-global/esnext.iterator.range.js 中的单元测试覆盖了大量边界情形可作为行为参照Array.from(Iterator.range(-1, 5)); // [-1, 0, 1, 2, 3, 4] Array.from(Iterator.range(-5, 1)); // [-5, -4, -3, -2, -1, 0] Array.from(Iterator.range(0, 0)); // []start end 且不含终点 空 Array.from(Iterator.range(0, 0, { step: 1, inclusive: true })); // []空区间 inclusive 也不产出 Array.from(Iterator.range(0, 0, -1)); // []负步长 起点等于终点 空 Array.from(Iterator.range(0, 0, { step: -1, inclusive: true })); // [0] Array.from(Iterator.range(0, -5, 1)); // []步长方向与区间方向相反 空特别值得注意的是小数步长测试测试文件第 27-30 行Array.from(Iterator.range(0, 1, 0.1)); // [0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]由于底层使用start step * count的累乘计算而非逐次累加小数步长会产生 IEEE 754 浮点精度误差如0.30000000000000004。这是规范的预期行为若需要精确的小数序列建议改用整数步长后再自行缩放。step 与 inclusive 参数的精确语义从 numeric-range-iterator.js 的实现来看参数的语义由构造函数与next()协作完成默认步长的方向推导第 32、45-47 行当步长未提供时ifIncrease end start判断区间方向默认步长取one递增即 1 / 1n或-one递减即 -1 / -1n。步长合法性校验第 48-54 行step类型必须与start一致number / bigint否则抛TypeErrorstep为NaN、±Infinity时抛RangeErrorstep 0且start ! end时抛RangeError——零步长且区间非空意味着死循环被明确禁止但如果start end空区间零步长是允许的。终点命中与 inclusive 判定第 78-90 行迭代器内部维护currentCount计数每次产出值为start step * currentCount。next()中先检查当前值是否恰好等于end命中终点则标记结束再根据inclusive与区间方向决定是否继续if (end start) { endCondition inclusiveEnd ? currentYieldingValue end : currentYieldingValue end; } else { endCondition inclusiveEnd ? end currentYieldingValue : end currentYieldingValue; } if (endCondition) { /* 结束 */ } return createIterResultObject(currentYieldingValue, false);即递增且inclusive时越过终点才停止递增且不含终点时达到或越过终点即停止保证终点不被产出。方向不匹配时的行为hitsEnd标志第 55、62 行在构造时通过end start ! step zero预判“步长方向与区间方向相反”此时迭代器在第一次next()就返回{ value: undefined, done: true }因此range(0, -5, 1)产出空序列。公开属性第 93-109 行当环境支持属性描述符DESCRIPTORS时迭代器实例通过访问器暴露start、end、step、inclusive四个只读属性不支持时则在实例上直接赋值。测试中可以通过iterator.start等属性检查配置。BigInt 支持与 Infinity 终点Iterator.range完整支持bigint并且签名中允许end为Infinity/-Infinity注意BigInt 本身没有 Infinity 字面量这里指的是 number 类型的Infinity。在 esnext.iterator.range.js 中BigInt 分支使用BigInt(0)、BigInt(1)作为zero、one基准。BigInt 用例来自 测试文件第 84-138 行const { range } Iterator; Array.from(range(BigInt(-1), BigInt(5))); // [BigInt(-1), ..., BigInt(4)] Array.from(range(BigInt(9007199254740991), BigInt(9007199254740992), { inclusive: true })); // 超出 MAX_SAFE_INTEGER 的范围用 BigInt 可精确表示BigInt 与 number 版本在类型混合上有严格限制测试验证了range(Infinity, BigInt(10), BigInt(0))、range(BigInt(0), BigInt(10), Infinity)均抛出TypeError即Infinity 只能以 number 类型出现且与 BigInt 混用会报错。异常处理边界RangeError 与 TypeError综合源码校验逻辑与 tests/unit-global/esnext.iterator.range.js 的断言可整理出完整的异常矩阵场景异常类型说明start为NaN或end为NaNRangeErrorNaN 无法参与区间比较start为±InfinityRangeError起点不能是无穷step为NaN对象选项或简写RangeError步长不能是 NaNstep为±InfinityRangeError步长不能是无穷step为0且start ! endRangeError避免死循环start类型非法对象、字符串等TypeError只接受 number / bigintend类型非法非 number/bigint/±InfinityTypeError同上option类型非法既非对象也非同类型数值TypeError第三个参数必须为对象或数值step类型与start不一致TypeError例如 number 区间配 bigint 步长测试中还验证了range(NaN, 0)、range(0, NaN)、range(NaN, NaN)均抛RangeError测试第 41-45 行以及类型错误相关断言测试第 79-82 行。这些行为对防御式编程非常有用在调用前不必自己写一堆校验直接捕获上述两类异常即可。Entry points 与引入方式官方文档给出的两个入口如下core-js/proposals/number-range core-js(-pure)/full/iterator/range入口一core-js/proposals/number-range该入口同时引入esnext.iterator.range、esnext.number.range与esnext.bigint.range见 proposals/number-range.js适合希望一次性拿到整套 range 能力的场景包括即将移除的旧版Number.range/BigInt.range。它依赖 esnext.iterator.constructor.js 以保证Iterator全局对象存在。入口二core-js(-pure)/full/iterator/rangefull/iterator/range.js 是一个较重的全量入口它不仅引入esnext.iterator.range还会拉入整个迭代器工具链drop、every、filter、find、flat-map、map、reduce、take、to-array等并将path.Iterator.range作为模块导出。若你只需要Iterator.range直接引入core-js/proposals/number-range更轻量若你的迭代器工具集本来就需要全套则可以使用core-js(-pure)/full/iterator/range。实际的模块入口是 modules/esnext.iterator.range.js它以{ target: Iterator, stat: true, forced: true }的方式注册为Iterator的静态方法forced: true表示即使宿主环境已有该方法也会强制覆盖为 core-js 版本。底层实现NumericRangeIterator 解析Iterator.range的核心并不在模块入口而在 internals/numeric-range-iterator.js 中定义的NumericRangeIterator。该构造函数由createIteratorConstructor创建配合InternalStateModule管理内部状态结构上包含三部分构造期校验与状态初始化第 20-71 行完成本文前述的全部参数校验NaN/Infinity/零步长/类型一致性并把start、end、step、inclusive、hitsEnd、currentCount、zero存入内部状态。hitsEnd预判方向不匹配导致“一步也走不了”的情况。next()迭代逻辑第 72-91 行按start step * currentCount公式惰性计算当前值配合inclusive与方向比较器决定何时返回done: true。整个迭代过程不预生成数组这是“惰性”与“省内存”的关键。只读访问器第 93-109 行在支持描述符的环境下为start、end、step、inclusive定义 gettersetter 为空实现且不可枚举。三个公共入口Iterator.range、Number.range、BigInt.range共用这一个迭代器类差异仅在于传入的typenumber/bigint与zero、one基准值。与旧版 Number.range / BigInt.range 的关系旧版静态方法同样基于NumericRangeIteratoresnext.number.range.jsNumber.range(start, end, option)固定以number、0、1构造esnext.bigint.range.jsBigInt.range(start, end, option)在typeof BigInt function时才注册固定以bigint、BigInt(0)、BigInt(1)构造。两者源码中均标注TODO: Remove from core-js4即官方计划在新主版本中移除。新代码应优先使用Iterator.range仅在需要兼容旧代码或旧浏览器时使用Number.range/BigInt.range。使用时把Iterator.range(a, b, c)与Number.range(a, b, c)视作等价即可——它们产出的都是同一个NumericRangeIterator。实战组合迭代器工具链使用Iterator.range返回的对象既是迭代器也是可迭代对象测试中assert.isIterator(iterator)与assert.isIterable(iterator)同时成立因此可以无缝接入for...of、Array.from、解构以及 core-js 的其他迭代器方法这些方法会随full/iterator/range入口一起引入。典型用法// 1. 直接 for...of 遍历 for (const n of Iterator.range(1, 6)) { console.log(n); // 1, 2, 3, 4, 5 } // 2. 转为数组 const pages Array.from(Iterator.range(1, 11, { inclusive: true })); // 1..10 // 3. 与迭代器工具链组合需引入 full/iterator/range const doubled Iterator.range(1, 6) .map(x x * 2) // 2, 4, 6, 8, 10 .filter(x x 4); // 6, 8, 10 // 4. 大区间惰性遍历内存占用恒定 let sum 0; for (const i of Iterator.range(0, 1e9, 1e6)) sum i; // 仅在需要时计算下一个值注意第 4 个例子正是惰性求值的价值所在1e9规模若用数组生成会占用 GB 级内存而NumericRangeIterator只保存起点、终点、步长与计数内存占用与区间长度无关。小结Iterator.range为 JS 提供了标准化、惰性、支持 number 与 bigint、可配置步长与开闭区间的数值范围迭代能力。通过本文可以掌握三种调用形式两参默认、对象 options、数值步长简写语义要点默认左闭右开、inclusive控制是否包含终点、步长方向与区间方向不一致时产出空序列、零步长非空区间抛错类型与边界number/bigint 不可混用NaN 与 Infinity 的异常规则明确引入方式轻量走core-js/proposals/number-range全量走core-js(-pure)/full/iterator/range底层原理NumericRangeIterator通过内部状态与start step * count惰性计算start/end/step/inclusive以只读属性暴露。在等待 TC39 提案进入正式标准Stage 4之前core-js 的这一实现是生产环境中最稳妥的 polyfill 选择。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →