String.prototype.matchAll S4
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2020
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案添加了 String.prototype.matchAll,它返回一个迭代器,用于遍历全局或粘性正则表达式的所有匹配项,包括捕获组。它解决了 String.prototype.match 在使用全局标志时不提供捕获组的问题,并且避免了手动使用 exec 或 replace 的副作用。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
String.prototype.matchAll
String.prototype.matchAll 的提案和规范。
Polyfill/Shim
参见 npm 上的 string.prototype.matchall 或 github 上的。
规范
你可以查看 markdown 格式 的规范,或渲染为 HTML 的版本。
理由
如果我有一个字符串,并且有一个粘性(sticky)或全局(global)的正则表达式,该表达式具有多个捕获组,我通常希望遍历所有匹配项。 目前,我的选择如下:
第一个示例不提供捕获组,因此不是一个选项。后两个示例都明显修改了 lastIndex - 对于内置的 RegExp 来说,这不是一个巨大的问题(超越了意识形态),但在 ES6/ES2015 中,对于可子类化的 RegExp,这是一种获取所有匹配所需信息的混乱方式。
因此,String#matchAll 将通过提供对所有捕获组的访问,并且不明显修改所涉及的正则表达式对象来解决这个用例。
迭代器与数组
许多用例可能想要一个匹配项的数组 - 但显然并非所有用例都需要。特别多的捕获组或大字符串,如果总是将所有匹配项收集到数组中,可能会产生性能影响。通过返回一个迭代器,如果调用者愿意,可以轻松地使用展开运算符或 Array.from 将其收集到数组中,但这不是必须的。
先前的讨论
- http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
- https://esdiscuss.org/topic/letting-regexp-method-return-something-iterable
- http://stackoverflow.com/questions/844001/javascript-regular-expressions-and-sub-matches
- http://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression
- http://stackoverflow.com/questions/19913667/javascript-regex-global-match-groups
- http://stackoverflow.com/questions/844001/javascript-regular-expressions-and-sub-matches
- http://blog.getify.com/to-capture-or-not/#manually-splitting-string
命名
选择 matchAll 这个名称是为了与 match 对应,并暗示将返回 所有 匹配项,而不仅仅是单个匹配。这包括这样的含义:提供的正则表达式将使用全局标志来查找字符串中的所有匹配。有人建议使用另一个名称 matches - 这遵循了 keys/values/entries 的先例,即复数名词表示返回迭代器。但是,includes 返回布尔值。当单词不明确是名词还是动词时,"复数名词"似乎不是一个明显的约定。
委员会反馈更新:ruby 使用 scan 这个词,但委员会不倾向于向 JavaScript 引入一个新词。有人建议使用 matchEach,但一些人对它与 forEach 的名称相似性感到不适,因为 API 相当不同。matchAll 似乎是大家最满意的名称。
在 2017 年 9 月的 TC39 会议上,有人提出了一个问题:"all" 是指 "所有重叠匹配" 还是 "所有非重叠匹配" - 其中 "重叠" 指 "从字符串中每个字符开始的匹配","非重叠" 指 "从字符串开头开始的所有匹配"。我们简要考虑了重命名该方法或添加一种实现两种语义的方法,但该异议被撤回。