为什么Javascript中的新函数"matchAll"返回一个迭代器而不是数组?

7

ES2020包含一个新的String.prototype.matchAll方法,它返回一个迭代器。我确定我错过了一些愚蠢/显而易见的东西,但我不明白为什么它不能只返回一个数组。

有人能解释一下这其中的逻辑吗?

编辑:仅澄清一下评论中的一些事情,我假设迭代器并没有简单地取代数组成为所有JS API返回多个值的新方式。如果我错过了这个备忘录,而且所有新的JS函数确实都返回迭代器,那么链接到该备忘录将百分之百地合格为有效答案。

但是,我怀疑这样的全面更改没有发生,Javascript的制造者在这个特定的方法中做出了具体的选择,使其返回一个迭代器...我想要理解的是这种选择的逻辑。


我猜这是exec的替代品,我们过去用它来代替matchAll以获得相同的功能,因为使用match中的g标志无法获取与exec中相同数量的匹配项,为了模仿相同的功能,提出了这个替代方案。 - Code Maniac
但是exec返回的是一个数组,而不是迭代器。从MDN中获悉:"exec()方法在指定的字符串中执行搜索匹配。返回一个结果数组或null。" - machineghost
它不像普通的数组,它会跟踪匹配的最后索引,并在下一次迭代中从那里开始搜索。该数组保存当前匹配和捕获组的值。 - Code Maniac
如果匹配成功,exec() 方法将返回一个数组(带有额外的属性 index 和 input;请参见下文),并更新正则表达式对象的 lastIndex 属性。 MDN - Code Maniac
1
如果你返回一个数组,函数调用完成时必须知道完整的结果。返回一个迭代器允许在请求下一个结果时进行评估。根据用例,这可以对内存和/或响应能力带来好处。 - t.niese
显示剩余9条评论
1个回答

8
这是在提议文档中描述的内容:
许多用例可能希望获得一个匹配项数组,但显然并非所有用例都需要。特别是大量捕获组或大字符串可能对始终将它们全部收集到数组中具有性能影响。通过返回迭代器,如果调用者愿意,可以使用展开运算符或Array.from轻松地将其收集到数组中,但不必这样做。
.matchAll是"懒惰的"。当使用迭代器时,正则表达式只有在迭代前一个匹配项后才会评估字符串中的下一个匹配项。这意味着,如果正则表达式很复杂,则可以提取前几个匹配项,然后您的JS逻辑可以使迭代器放弃尝试进一步匹配。
以下是演示延迟评估的一个简单示例:

for (const match of 'axxxxxxxxxxxxxxxxxxxxxxxxxxxxy'.matchAll(/a|(x+x+)+y./g)) {
  if (match[0] === 'a') {
    console.log('Breaking out');
    break;
  }
}
console.log('done');

如果没有 break,正则表达式将继续尝试第二次匹配,这将导致非常昂贵的操作。

如果 matchAll 返回一个数组,并在创建数组时立即迭代所有匹配项,则无法退出。


它正在工作,但我的TypeScript显示: ESLint:迭代器/生成器需要regenerator-runtime,这对于本指南来说太重了,不允许它们。另外,应该避免使用循环,而应该使用数组迭代。(no-restricted-syntax) 有什么办法可以适应它吗? - undefined
你可以使用传统的 for (let i = 0; 来遍历匹配项,以避免使用迭代器。这仍然需要一个“循环”,但很难避免,所以不要担心。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接