String.prototype.matchAll()
===========================

**`matchAll()`** 方法返回一个迭代器，该迭代器包含了检索字符串与正则表达式进行匹配的所有结果（包括捕获组）。

尝试一下
----

语法
--


```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[@@matchAll]()`。

示例
--

### Regexp.prototype.exec() 和 matchAll()

如果没有 `matchAll()` 方法，仍然可以使用带有 `g` 标志的正则表达式调用 `regexp.exec()` 来在循环中获取所有匹配结果：


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

while ((match = regexp.exec(str)) !== null) {
  console.log(
    `找到 ${match[0]} 起始位置=${match.index} 结束位置=${regexp.lastIndex}。`,
  );
}
// 找到 football 起始位置=6 结束位置=14。
// 找到 foosball 起始位置=16 结束位置=24。
```


如果有 `matchAll()` 方法，则可以避免使用 `while` 循环和带有 `g` 标志的 `exec`。相反，你可以获得一个迭代器，以便使用更方便的 `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(
    `找到 ${match[0]} 起始位置=${match.index} 结束位置=${
 match.index + match[0].length
 }.`,
  );
}
// 找到 football 起始位置=6 结束位置=14.
// 找到 foosball 起始位置=16 结束位置=24.

// 匹配迭代器在 for...of 迭代后用尽
// 再次调用 matchAll 以创建新的迭代器
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 的非正则对象调用 matchAll()

如果一个对象有一个 `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."]]
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-string.prototype.matchall |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `core-js` 中 `String.prototype.matchAll` 的 polyfill
* `String.prototype.match()`
* 在 JavaScript 中使用正则表达式
* 捕获组
* `RegExp`
* `RegExp.prototype.exec()`
* `RegExp.prototype.test()`
* `RegExp.prototype[@@matchAll]()`