One difference is that match
returns an array and matchAll
returns an iterator, but there are several other details to consider.
When the regex doesn’t have the flag g
, match
returns an array containing only the first occurrence, plus some related information (such as capture groups). But when you have the flag g
, the result contains only the pouch, without further information:
let s = 'a1 b2 c3 d4';
console.log('---match---');
// sem flag g, pega somente a primeira ocorrência, com informações adicionais
let result = s.match(/[a-z](\d)/);
for (let i in result) console.log(`${i}=${result[i]}`);
console.log('---matchAll---');
// com flag g, pega todas as ocorrências, sem informações adicionais
result = s.match(/[a-z](\d)/g);
for (let i in result) console.log(`${i}=${result[i]}`);
The regex is [a-z](\d)
(a letter followed by a number, the number being in parentheses, which forms a capture group).
Without the flag g
, the returned array has:
- in first position, the first occurrence (
a1
)
- in the other positions, the capture groups (in this case, we only have one group, containing the digit
1
)
- the property
index
containing the index where the match was found (a1
is at the zero index of the string)
- the property
input
containing a copy of the entire string
- the property
groups
, which contains only the appointed groups (so the group containing the digit is not there).
But if we use the flag g
, the array contains only the snippets you have given match (only a1
, b2
, etc), without the additional information (no groups, index
, etc.).
Before matchAll
, the only way to get the additional information for all occurrences was by using exec
:
let s = 'a1 b2 c3 d4';
let r = /[a-z](\d)/g;
let match;
while (match = r.exec(s)) {
console.log('----');
for (let i in match) console.log(`${i}=${match[i]}`);
}
Note that now every call from exec
returns an array containing the match and the additional information.
But with matchAll
it’s a little simpler to do the same thing:
let s = 'a1 b2 c3 d4';
for (const match of s.matchAll(/[a-z](\d)/g)) {
console.log('----');
for (let i in match) console.log(`${i}=${match[i]}`);
}
And how matchAll
returns an iterator, you can use it with for..of
(as in the example above), with spread to create an array with the results ([...s.matchAll(/[a-z](\d)/g)]
), etc..
One detail is that with matchAll
, the regex must have the flag g
, otherwise will give error (and a curiosity is that if you use exec
without the flag g
, he gets into loop infinite, since exec
search from the lastIndex
, but without the flag g
this value is always zero, so in this case she will always find a match).
By the way, this is another detail: exec
updates the lastIndex
from regex, then each call looks from this position. But matchAll
does not touch the lastIndex
:
let s = 'a1 b2 c3 d4';
let r = /[a-z](\d)/g;
let match;
while (match = r.exec(s)) {
console.log(r.lastIndex); // o índice vai sendo atualizado conforme encontra os matches
}
let r2 = /[a-z](\d)/g;
for (const m of s.matchAll(r2)) {
console.log(r2.lastIndex); // não muda, é sempre zero
}