String.prototype.matchAll()

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流浏览器均已支持。

matchAll() 方法用于 String 值,它会返回一个迭代器,该迭代器包含字符串与 正则表达式 匹配的所有结果,包括 捕获组

试一试

const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";

const array = [...str.matchAll(regexp)];

console.log(array[0]);
// Expected output: Array ["test1", "e", "st1", "1"]

console.log(array[1]);
// Expected output: Array ["test2", "e", "st2", "2"]

语法

js
matchAll(regexp)

参数

regexp

一个正则表达式对象,或者任何具有 Symbol.matchAll 方法的对象。

如果 regexp 不是 RegExp 对象且不具有 Symbol.matchAll 方法,它将通过使用 new RegExp(regexp, 'g') 被隐式转换为 RegExp

如果 regexp 是一个正则表达式,则必须设置全局 (g) 标志,否则会抛出 TypeError

返回值

一个 可迭代的迭代器对象(不可重新启动),包含匹配项,或者在未找到匹配项时返回一个空迭代器。迭代器产生的每个值都是一个数组,其形状与 RegExp.prototype.exec() 的返回值相同。

异常

TypeError

如果 regexp 是一个正则表达式 并且没有设置全局 (g) 标志(其 flags 属性不包含 "g"),则会抛出此错误。

描述

String.prototype.matchAll 的实现除了对正则表达式是否全局进行额外输入验证之外,主要就是调用参数的 Symbol.matchAll 方法,并将字符串作为第一个参数传入。实际的实现来自 RegExp.prototype[Symbol.matchAll]()

示例

Regexp.prototype.exec() 和 matchAll()

matchAll() 出现之前,可以通过在循环中使用 regexp.exec() 调用(以及设置了 g 标志的正则表达式)来获取所有匹配项。

js
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
let match;

while ((match = regexp.exec(str)) !== null) {
  console.log(
    `Found ${match[0]} start=${match.index} end=${regexp.lastIndex}.`,
  );
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.

现在有了 matchAll(),你可以避免使用 while 循环和带 gexec。取而代之的是,你可以获取一个迭代器,并使用更方便的 for...of数组展开Array.from() 构造。

js
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
const matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(
    `Found ${match[0]} start=${match.index} end=${
      match.index + match[0].length
    }.`,
  );
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.

// matches iterator is exhausted after the for...of iteration
// Call matchAll again to create a new iterator
Array.from(str.matchAll(regexp), (m) => m[0]);
// [ "football", "foosball" ]

如果缺少 g 标志,matchAll 将抛出异常。

js
const regexp = /[a-c]/;
const str = "abc";
str.matchAll(regexp);
// TypeError

matchAll 内部会创建一个 regexp 的克隆——因此,与 regexp.exec() 不同,在扫描字符串时 lastIndex 不会改变。

js
const regexp = /[a-c]/g;
regexp.lastIndex = 1;
const str = "abc";
Array.from(str.matchAll(regexp), (m) => `${regexp.lastIndex} ${m[0]}`);
// [ "1 b", "1 c" ]

然而,这意味着与在循环中使用 regexp.exec() 不同,你无法通过修改 lastIndex 来让正则表达式前进或后退。

比 String.prototype.match() 更方便地访问捕获组

matchAll 另一个引人注目的原因是它改进了对捕获组的访问。

当使用带有全局 g 标志的 match() 时,捕获组会被忽略。

js
const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";

str.match(regexp); // ['test1', 'test2']

使用 matchAll,你可以轻松访问捕获组。

js
const array = [...str.matchAll(regexp)];

array[0];
// ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4]
array[1];
// ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4]

将 matchAll() 与实现了 [Symbol.matchAll]() 的非 RegExp 对象一起使用

如果一个对象具有 Symbol.matchAll 方法,它就可以被用作自定义匹配器。Symbol.matchAll 的返回值将成为 matchAll() 的返回值。

js
const str = "Hmm, this is interesting.";

str.matchAll({
  [Symbol.matchAll](str) {
    return [["Yes, it's interesting."]];
  },
}); // returns [["Yes, it's interesting."]]

规范

规范
ECMAScript® 2026 语言规范
# sec-string.prototype.matchall

浏览器兼容性

另见