JavaScript Regex Methods Table
| Method | Returns | Field note |
|---|---|---|
re.test(str) | boolean | The existence check - fastest when you only need yes/no |
str.match(re) | Array or null | With g: all matches, no groups; without g: full match + groups |
str.matchAll(re) | Iterator of matches | REQUIRES g flag; each entry has .groups - the extraction king |
str.replace(re, fn) | New string | Function replacer receives groups as args - dynamic substitution |
str.replaceAll(re, fn) | New string | re must have g flag or it throws - the explicit contract |
str.search(re) | Index or -1 | First position only; ignores g flag |
re.exec(str) | Array or null | Advances lastIndex with g - stateful loops, reset with re.lastIndex = 0 |
re.source | The pattern text | The regex itself as a string - debugging and dynamic building |
Regex methods live on two prototypes: RegExp (test, exec) and String (match, matchAll, replace, replaceAll, search, split). The table below is the working eight - and the single distinction behind most regex bugs: the g flag changes the RETURN SHAPE of match, advances exec's lastIndex between calls, and is REQUIRED by matchAll and replaceAll.
Bottom line: the method picker follows the question. Existence: test (fastest, stops at first hit). One match with groups: match without g (full match plus capture array). All matches with groups: matchAll (the iterator; g required). Rewrite: replace with a string or function replacer. The gotcha family: match WITH g returns full matches only (groups lost), and exec with g advances lastIndex - reset it to 0 or the loop stops early.
The honest part: replace's function replacer is the upgrade that retires half of regex complexity. Instead of capture-group puzzles in the replacement string, the function receives each matched value and groups as arguments and returns the replacement computed in plain JavaScript - dynamic substitution the string syntax cannot express.
How to use
- Pick by question: exists (test), first match (match), all matches (matchAll), rewrite (replace/replaceAll).
- Check the g flag against intent: g on match returns full matches only - groups need matchAll; exec loops need g plus lastIndex reset.
- Use the function replacer for computed substitutions - it receives the match and all groups as arguments, in order.
Frequently asked questions
Why does str.match(re) sometimes return groups and sometimes not?
The g flag changes the return shape: without g, match returns an array where [0] is the full match and [1..] are capture groups, plus .index. WITH g, match returns an array of full matches only - no groups, no index. Code that expects groups breaks when someone adds the g flag. The uniform alternative is matchAll, which always yields full match objects with groups regardless - the modern extraction method.
Why does my exec loop only find the first match?
Because exec with the g flag is STATEFUL: it stores lastIndex on the regex object and starts the next call from there. The loop pattern works (while ((m = re.exec(s)) !== null)), but if the loop exits early, the regex's lastIndex stays where it stopped - the next loop over the SAME regex object starts mid-string. Reset re.lastIndex = 0 before reusing, or create a fresh regex per loop.
When should the replace callback replace the string pattern?
When the replacement is COMPUTED from the match. The string form handles static text plus $1/$2 group inserts; the function form receives (match, group1, group2, offset, string) and returns anything JavaScript can compute - capitalizing words, converting units, redacting by rule. It is also the only form where the replacement can reference the match's position (the offset argument).
Why does matchAll throw where match does not?
matchAll requires the g flag by design - it always returns all matches, so the flag is the explicit contract, and omitting it throws a TypeError instead of silently returning one match. The symmetry: match without g returns one match object, matchAll with g returns an iterator of match objects with the same shape (full match, groups, index). The iterator is lazy - spread it or use for...of to consume.