|
| 1 | +project_path: /web/_project.yaml |
| 2 | +book_path: /web/updates/_book.yaml |
| 3 | +description: Chrome 73 introduces the String.prototype.matchAll() method. It behaves similarly to match(), but offers a simple way to iterate over matches, especially when you need access to capture groups. |
| 4 | + |
| 5 | +{# wf_published_on: 2019-02-07 #} |
| 6 | +{# wf_updated_on: 2019-01-30 #} |
| 7 | +{# wf_featured_image: /web/updates/images/generic/js.png #} |
| 8 | +{# wf_tags: chrome73,javascript,regex #} |
| 9 | +{# wf_featured_snippet: Chrome 73 introduces the <code>String.prototype.matchAll()</code> method. It behaves similarly to <code>match()</code>, but offers a simple way to iterate over matches, especially when you need access to capture groups. #} |
| 10 | +{# wf_blink_components: Blink>JavaScript>Language #} |
| 11 | + |
| 12 | +# Better match results with String.prototype.matchAll() {: .page-title } |
| 13 | + |
| 14 | +{% include "web/_shared/contributors/josephmedley.html" %} |
| 15 | + |
| 16 | +Chrome 73 introduces the `String.prototype.matchAll()` method. It behaves |
| 17 | +similarly to `match()`, but returns an iterator with all regular expression |
| 18 | +matches in a global or sticky regular expression. This offers a simple way to |
| 19 | +iterate over matches, especially when you need access to capture groups. |
| 20 | + |
| 21 | +## What's wrong with match()? |
| 22 | + |
| 23 | +The short answer is nothing, unless you're trying to return global matches with |
| 24 | +capturing groups. Here's a programming puzzle for you. Consider the following |
| 25 | +code: |
| 26 | + |
| 27 | +```js |
| 28 | +const regex = /t(e)(st(\d?))/g; |
| 29 | +const string = 'test1test2'; |
| 30 | +const results = string.match(regex); |
| 31 | +console.log(results); |
| 32 | +// → ['test1', 'test2'] |
| 33 | +``` |
| 34 | + |
| 35 | +Run this in a console and notice that it returns an array containing the |
| 36 | +strings `'test1'` and `'test2'`. If I remove the g flag from the regular |
| 37 | +expression what I get has all of my capturing groups, but I only get the first |
| 38 | +match. It looks like this: |
| 39 | + |
| 40 | +```js |
| 41 | +['test1', 'e', 'st1', '2', index: 0, input: 'test1test2', groups: undefined] |
| 42 | +``` |
| 43 | + |
| 44 | +This string contains a second possible match beginning with `'test2'` but I don't |
| 45 | +have it. Now here's the puzzle: how do I get all of the capturing groups for |
| 46 | +each match? The [explainer for the String.prototype.matchAll() |
| 47 | +proposal](https://github.com/tc39/proposal-string-matchall) |
| 48 | +shows two possible approaches. I won't describe them because hopefully you |
| 49 | +won't need them much longer. |
| 50 | + |
| 51 | +## String.prototype.matchAll() |
| 52 | + |
| 53 | +What would the explainer examples look like with `matchAll()`? Have a look. |
| 54 | + |
| 55 | +```js |
| 56 | +const regex = /t(e)(st(\d?))/g; |
| 57 | +const string = 'test1test2'; |
| 58 | +const matches = string.matchAll(regex); |
| 59 | +for (const match of matches) { |
| 60 | + console.log(match); |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +There are a few things to note about this. Unlike `match()` which returns an |
| 65 | +array on a global search, `matchAll()` returns an iterable object that works |
| 66 | +beautifully with `for...of` loops. The iterable object produces an array for |
| 67 | +each match, including the capturing groups with a few extras. If you print |
| 68 | +these to the console they'll look like this: |
| 69 | + |
| 70 | +```js |
| 71 | +['test1', 'e', 'st1', '2', index: 0, input: 'test1test2', groups: undefined] |
| 72 | +['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined] |
| 73 | +``` |
| 74 | + |
| 75 | +You may notice that the value for each match is an array in exactly the same |
| 76 | +format returned by `match()` for non-global regular expressions. |
| 77 | + |
| 78 | +## Bonus material |
| 79 | + |
| 80 | +This is mainly for people who are new to regular expressions or who aren't |
| 81 | +experts at it. You may have noticed the results of both match() and matchAll() |
| 82 | +(for each iteration) are arrays with some additional named properties. While |
| 83 | +preparing this article, I noticed that these properties have some documentation |
| 84 | +deficiencies on MDN (which |
| 85 | + [I've fixed](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#Return_value)). |
| 86 | + Here's a quick description. |
| 87 | + |
| 88 | +<dl> |
| 89 | + <dt><code>index</code></dt> |
| 90 | + <dd>The index of the first result in the original string. In the above example <code>test2</code> starts at position 5 hence <code>index</code> has the value 5.</dd> |
| 91 | + <dt><code>input</code></dt> |
| 92 | + <dd>The complete string that <code>matchAll()</code> was run against. In my example, that was <code>'test1test2'</code>.</dd> |
| 93 | + <dt><code>groups</code></dt> |
| 94 | + <dd>Contains the results of any <a href='https://mathiasbynens.be/notes/es-regexp-proposals#named-capture-groups'>named capturing |
| 95 | +groups</a> specified in your regular expression.</dd> |
| 96 | +</dl> |
| 97 | + |
| 98 | +## Conclusion |
| 99 | + |
| 100 | +If I've missed anything please let me know in the comments below. You can read more about recent changes to JavaScript [in previous |
| 101 | +updates](/web/updates/tags/javascript) or on [the V8 website](https://v8.dev/). |
| 102 | + |
| 103 | +{% include "web/_shared/helpful.html" %} |
| 104 | + |
| 105 | +{% include "web/_shared/rss-widget-updates.html" %} |
0 commit comments