JavaScript Regex Methods Table

MethodReturnsField note
re.test(str)booleanThe existence check - fastest when you only need yes/no
str.match(re)Array or nullWith g: all matches, no groups; without g: full match + groups
str.matchAll(re)Iterator of matchesREQUIRES g flag; each entry has .groups - the extraction king
str.replace(re, fn)New stringFunction replacer receives groups as args - dynamic substitution
str.replaceAll(re, fn)New stringre must have g flag or it throws - the explicit contract
str.search(re)Index or -1First position only; ignores g flag
re.exec(str)Array or nullAdvances lastIndex with g - stateful loops, reset with re.lastIndex = 0
re.sourceThe pattern textThe regex itself as a string - debugging and dynamic building
Reference: the MDN RegExp reference. The two-stateful-method facts that bite: exec with the g flag advances lastIndex between calls (the loop pattern), and match CHANGES ITS RETURN SHAPE depending on the g flag (all matches vs full-match-with-groups) - code that expects one shape breaks when the flag changes. Bottom line: test for existence, match for one shot, matchAll for extraction with groups, replaceAll for rewriting - and remember matchAll throws without the g flag, the explicit contract the others let slide. Related tools: regex groups table (what the captures hold), extract numbers and extract urls for the no-code versions, and string methods table for the non-regex siblings.

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

  1. Pick by question: exists (test), first match (match), all matches (matchAll), rewrite (replace/replaceAll).
  2. Check the g flag against intent: g on match returns full matches only - groups need matchAll; exec loops need g plus lastIndex reset.
  3. 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.

Related tools