If youβve ever dealt with strings in JavaScript, chances are you came across the String#replace
method. String.prototype.replace(searchValue, replacement)
returns a string with some matches replaced, based on the parameters you specify:
'abc'.replace('b', '_');
// β 'a_c'
'ππππ'.replace('π', 'π₯');
// β 'π₯πππ'
A common use case is replacing all instances of a given substring. However, String#replace
doesnβt directly address this use case. When searchValue
is a string, only the first occurrence of the substring gets replaced:
'aabbcc'.replace('b', '_');
// β 'aa_bcc'
'ππππππππ'.replace('π', 'π₯');
// β 'π₯πππππππ'
To work around this, developers often turn the search string into a regular expression with the global (g
) flag. This way, String#replace
does replace all matches:
'aabbcc'.replace(/b/g, '_');
// β 'aa__cc'
'ππππππππ'.replace(/π/g, 'π₯');
// β 'π₯π₯ππππππ'
As a developer, itβs annoying to have to do this string-to-regexp conversion if all you really want is a global substring replacement. More importantly, this conversion is error-prone, and a common source of bugs! Consider the following example:
const queryString = 'q=query+string+parameters';
queryString.replace('+', ' ');
// β 'q=query string+parameters' β
// Only the first occurrence gets replaced.
queryString.replace(/+/, ' ');
// β SyntaxError: invalid regular expression β
// As it turns out, `+` is a special character within regexp patterns.
queryString.replace(/\+/, ' ');
// β 'q=query string+parameters' β
// Escaping special regexp characters makes the regexp valid, but
// this still only replaces the first occurrence of `+` in the string.
queryString.replace(/\+/g, ' ');
// β 'q=query string parameters' β
// Escaping special regexp characters AND using the `g` flag makes it work.
Turning a string literal like '+'
into a global regular expression is not just a matter of removing the '
quotes, wrapping it into /
slashes, and appending the g
flag β we must escape any characters that have a special meaning in regular expressions. This is easy to forget, and hard to get right, since JavaScript doesnβt offer a built-in mechanism to escape regular expression patterns.
An alternate workaround is to combine String#split
with Array#join
:
const queryString = 'q=query+string+parameters';
queryString.split('+').join(' ');
// β 'q=query string parameters'
This approach avoids any escaping but comes with the overhead of splitting the string into an array of parts only to glue it back together.
Clearly, none of these workarounds are ideal. Wouldnβt it be nice if a basic operation such as global substring replacement would be straightforward in JavaScript?
String.prototype.replaceAll
#
The new String#replaceAll
method solves these problems and provides a straightforward mechanism to perform global substring replacement:
'aabbcc'.replaceAll('b', '_');
// β 'aa__cc'
'ππππππππ'.replaceAll('π', 'π₯');
// β 'π₯π₯ππππππ'
const queryString = 'q=query+string+parameters';
queryString.replaceAll('+', ' ');
// β 'q=query string parameters'
For consistency with the pre-existing APIs in the language, String.prototype.replaceAll(searchValue, replacement)
behaves exactly like String.prototype.replace(searchValue, replacement)
, with the following two exceptions:
- If
searchValue
is a string, thenString#replace
only replaces the first occurrence of the substring, whileString#replaceAll
replaces all occurrences. - If
searchValue
is a non-global RegExp, thenString#replace
replaces only a single match, similar to how it behaves for strings.String#replaceAll
on the other hand throws an exception in this case, since this is probably a mistake: if you really want to βreplace allβ matches, youβd use a global regular expression; if you only want to replace a single match, you can useString#replace
.
The important piece of new functionality lies in that first item. String.prototype.replaceAll
enriches JavaScript with first-class support for global substring replacement, without the need for regular expressions or other workarounds.
A note on special replacement patterns #
Worth calling out: both replace
and replaceAll
support special replacement patterns. Although these are most useful in combination with regular expressions, some of them ($$
, $&
, $`
, and $'
) also take effect when performing simple string replacement, which can be surprising:
'xyz'.replaceAll('y', '$$');
// β 'x$z' (not 'x$$z')
In case your replacement string contains one of these patterns, and you want to use them as-is, you can opt-out of the magical substitution behavior by using a replacer function that returns the string instead:
'xyz'.replaceAll('y', () => '$$');
// β 'x$$z'
String.prototype.replaceAll
support #
- Chrome: supported since version 85
- Firefox: supported since version 77
- Safari: supported since version 13.1
- Node.js: supported since version 16
- Babel: supported