String matchAll vs Lodash for Regex Matching

The introduction of String.prototype.matchAll in ECMAScript 2020 provides a native, streamlined way to capture multiple regular expression matches alongside their capturing groups. Historically, JavaScript lacked an intuitive built-in approach for this task, leading developers to rely on utility libraries like Lodash or verbose RegExp.prototype.exec loops to parse complex string patterns. By delivering an iterable containing complete match arrays, matchAll makes external regex utility patterns and Lodash workarounds obsolete for string extraction.

The Limitation of Traditional Native Methods

Prior to matchAll, developers primarily relied on two native options: String.prototype.match and RegExp.prototype.exec.

When used with the global flag (/g), String.prototype.match returns all matching substrings but discards capturing groups, match indices, and named capture groups. To preserve capturing groups, developers were forced to use RegExp.prototype.exec inside a mutable while loop, manually tracking the state of the regular expression:

const regex = /t(e)(st(\d?))/g;
const text = 'test1test2';
let match;

while ((match = regex.exec(text)) !== null) {
  console.log(match);
}

This approach is prone to errors, such as infinite loops if the regex lacks the global flag or if state management fails.

How Lodash Filled the Gap

Because native regex extraction was cumbersome, developers regularly turned to Lodash to handle repetitive string processing and token extraction. Functions like _.words provided simpler string-splitting mechanisms, while custom Lodash pipelines were frequently used to wrap and map over RegExp.exec iterations. Developers used functional utilities to iterate cleanly over strings, transform capture groups, and avoid maintaining stateful while loops directly in application code.

While Lodash does not feature an exact _.matchAll function, developers heavily depended on its collection and string processing methods to compensate for JavaScript's native shortcomings regarding iterative regex parsing.

How String.prototype.matchAll Replaces Utility Helpers

String.prototype.matchAll completely solves the limitations of match and the verbosity of exec. Calling matchAll returns an iterator of match objects, each containing the full match, all capture groups, the index where the match was found, the original input string, and any named groups defined in the pattern.

Because the returned value is an iterable, it integrates naturally with modern JavaScript features like for...of loops, array destructuring, and Array.from:

const regex = /t(e)(st(\d?))/g;
const text = 'test1test2';

// Clean array of matches with all groups preserved
const matches = [...text.matchAll(regex)];

matches.forEach(match => {
  console.log(match[0]); // full match
  console.log(match[1]); // first capture group
  console.log(match.index); // start index
});

Unlike RegExp.prototype.exec, matchAll handles regex state internally without mutating the original lastIndex on the regular expression, ensuring safer, pure functional operations.

Eliminating the Need for External Helpers

With String.prototype.matchAll, the need to rely on external library routines or verbose loops to extract structured token data disappears. Developers gain the following advantages without importing utility libraries:

  1. Group Retention: Capture groups and named capture groups are preserved across all global matches.
  2. Immutability: Internal regex tracking prevents side effects without manual resets of regex.lastIndex.
  3. Idiomatic Processing: Native iterables allow immediate transformation via standard array methods like .map(), .filter(), and .reduce().
  4. Reduced Bundle Size: Removing third-party string and regex iteration wrappers reduces application dependencies and overall bundle overhead.