matchall返回regexpstringiterator,仅支持for...of、展开运算符或.next();必须带g标志,支持命名捕获,结果不可重复遍历,safari 13.1+才兼容。

matchAll 返回的是迭代器,不能直接用 for...in 遍历
很多人写 for (const match in str.matchAll(regex)),结果什么也拿不到——matchAll 返回的是一个 RegExpStringIterator,它只支持 for...of、展开运算符或手动调用 .next(),for...in 遍历的是对象属性名,而这个迭代器没有可枚举属性。
正确做法是:
const str = "a1 b22 c333";
const regex = /(\w)(\d+)/g;
for (const match of str.matchAll(regex)) {
console.log(match);
}
每次 match 是一个 Array,包含完整匹配项(match[0])、各捕获组(match[1], match[2]…),还附带 .index 和 .groups(如果用了命名捕获)。
命名捕获组必须显式写 g 标志,否则 matchAll 不工作
matchAll 要求正则必须带 g(全局)标志,否则会抛出 TypeError: String.prototype.matchAll called with a non-global RegExp。这点和 match 不同——match 没 g 时返回首个匹配,但 matchAll 没 g 就直接拒掉。
常见错误写法:
/(\w)(?<num>\d+)/.matchAll(str) // ❌ 报错:缺少 g</num>
正确写法:
/(\w)(?<num>\d+)/g.matchAll(str) // ✅</num>
命名捕获组的值通过 match.groups.num 访问,比靠索引更安全,尤其当正则里有可选组或嵌套时。
matchAll 不缓存结果,多次遍历需重新调用
str.matchAll(regex) 每次调用都创建新迭代器,且该迭代器只能消费一次。下面代码只会打印第一轮结果,第二轮为空:
const matches = str.matchAll(regex); for (const m of matches) console.log(m); // ✅ for (const m of matches) console.log(m); // ❌ 无输出
如果需要多次使用,要么重新调用 matchAll,要么转成数组:
- 临时用:[...str.matchAll(regex)] —— 适合小数据,注意内存开销
- 频繁读取:用
Array.from(str.matchAll(regex)),语义更明确 - 流式处理大数据:坚持用
for...of一次性消费,避免转数组
matchAll 在 Safari 13.1+ 才支持,旧环境要降级
如果你的项目还要兼容 Safari ≤13 或 iOS Safari ≤13.3,matchAll 会是 undefined。不能只靠 if (str.matchAll) 判断——有些老版本存在但行为异常(比如不支持命名捕获)。
稳妥的降级方案是用 while + regex.exec(str),但要注意手动维护 lastIndex:
const regex = /(\w)(\d+)/g;
let match;
while ((match = regex.exec(str)) !== null) {
console.log(match); // 同 matchAll 的单次 match 结构
}
注意:exec 依赖正则对象的 lastIndex,所以不能复用同一个正则实例去匹配不同字符串,除非每次重置 regex.lastIndex = 0。
真正容易被忽略的是:matchAll 的每个 match 数组是“活”的——它和原正则的 groups、index 是绑定的,但数组本身不可扩展,修改 match.length 或加属性会静默失败;另外,如果正则里有 ^ 或 $,在全局模式下它们仍只匹配开头/结尾,不会因 matchAll 改变语义。











