String.prototype.replaceAll()

Returns a new string with every match of a pattern swapped for a replacement.

Signature
replaceAll(pattern, replacement)
  • Added in JavaScript ES2021

Parameters

ParameterTypeDescription
$patternstring | RegExp | { [Symbol.replace](): any }A string or an object with a Symbol.replace method — typically a regular expression, which must carry the global (g) flag. Any value without a Symbol.replace method is coerced to a string and matched literally.
$replacementstring | ((match: string, ...args: any[]) => string)A string or a function, with the same semantics as the replacement argument of String.prototype.replace().

Return value

stringA new string, with all matches of a pattern replaced by a replacement.

Errors

Throws a TypeError if pattern is a regex whose flags do not contain "g".

Changelog

  • PHP ES2021Introduced. Before this, replacing every occurrence of a literal substring required a global regex with escaped metacharacters.

replaceAll() exists so you never have to build a global regex just to swap a literal substring. Before ES2021 the idiom was s.replace(new RegExp(escapeRegExp(needle), "g"), value), and forgetting the escaping step was a reliable source of bugs — a needle containing ., * or ( would match the wrong things or throw.

The regex rule

You may still pass a regex, but it must have the g flag. A non-global regex throws a TypeError rather than quietly behaving like replace(). This is deliberate: a method called replaceAll that replaced one thing would be worse than an error.

Everything else matches replace()

The replacement argument behaves identically to replace(): $&, $1, $<name> and $$ are expanded in a string replacement, and a function replacement is called once per match with the match, groups, offset and input. That includes the dollar-sign trap — a replacement string built from user data still needs $$ escaping, or a function.

When to still use a regex

Case-insensitive replacement, word boundaries, or anything pattern-shaped. For a plain literal, the string form is faster to read and impossible to get wrong.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Swap every path separator when normalising a file path
  • Strip all occurrences of a character from an identifier
  • Fill a template by replacing every named placeholder
  • Convert every tab in a block of code to spaces

Frequently asked questions

What is the difference between replace and replaceAll?

replace() substitutes only the first match when given a string or non-global regex, while replaceAll() substitutes every match. replaceAll() also rejects a non-global regex with a TypeError, so its name always matches its behaviour.

Why does replaceAll throw a TypeError with my regex?

Because the regex is missing the global g flag, which replaceAll() requires by specification. Change /foo/ to /foo/g, or pass the pattern as a plain string if you only need a literal match.

Which browsers support String.prototype.replaceAll?

It has been available across browsers since August 2020 and is part of ES2021. Anything older needs the s.replace(new RegExp(escaped, "g"), value) fallback with the needle's regex metacharacters escaped.

More examples

No regex escaping needed

replaceAll treats "." as a literal dot and produces "cost: 1,5, tax: 0,2". The unescaped RegExp treats it as "any character" and turns the whole string into commas — exactly the bug replaceAll was added to prevent.

Example · javascript
const text = "cost: 1.5, tax: 0.2";

// A literal dot, matched literally
console.log(text.replaceAll(".", ","));

// The old way needed escaping; unescaped it matches everything
console.log(text.replace(new RegExp(".", "g"), ","));

console.log(text.replace(new RegExp("\\.", "g"), ","));

Filling a template

The loop replaces both {name} occurrences, giving "Ada works as an engineer. Ask Ada.". The single-pass version scans once with a global regex and looks each key up, falling back to "?" for unknown placeholders.

Example · javascript
const values = { name: "Ada", role: "engineer" };
let out = "{name} works as an {role}. Ask {name}.";

for (const [k, v] of Object.entries(values)) {
  out = out.replaceAll(`{${k}}`, v);
}
console.log(out);

// Or in one pass with a function replacement
const tpl = "{name} is an {role}";
console.log(tpl.replaceAll(/\{(\w+)\}/g, (_, k) => values[k] ?? "?"));

Counting while replacing

The output is "555-****, 555-****" and a count of 2. Because the replacer function runs once per match, it doubles as a cheap way to count matches without a separate matchAll pass.

Example · javascript
let hits = 0;
const masked = "555-0100, 555-0199".replaceAll(/\d{4}\b/g, (m) => {
  hits++;
  return "****";
});

console.log(masked);
console.log(hits);

Discussion

  • Be the first to comment on this lesson.