replaceAll()

ES2021+

Returns a new string with every occurrence of the search value replaced, whether the search value is a plain string or a global regular expression. Added in ES2021, it fixes the classic surprise of replace() by making all-occurrence replacement the default for string patterns, with no regex or g flag required. The original string is never modified.

Syntax

string.replaceAll(searchValue, replaceValue)

Parameters

searchValue string | RegExp

The value to search for (must be global if RegExp)

replaceValue string | Function

The replacement string or function

Return Value

string

A new string with all replacements made

Examples

JavaScript
const str = 'Hello World World';
console.log(str.replaceAll('World', 'JS'));
Output:
// 'Hello JS JS'

📌 When to Use

Use replaceAll() whenever you mean 'replace every occurrence of this literal text' and the pattern does not need regex power: stripping all spaces and punctuation from phone numbers, swapping every occurrence of a placeholder token, normalizing line endings, or sanitizing every instance of a character sequence in user input. Before ES2021 the only correct all-occurrence idioms were a global regex, which forced you to escape any metacharacters in dynamic search text, or the split-join trick, which allocates an intermediate array; replaceAll() with a string argument treats the search text literally, so user-supplied search strings are safe by construction with no escaping ceremony. That makes it the right default for find-and-replace features driven by user input. It accepts a regex too, but only a global one, throwing a TypeError otherwise, so with regexes it adds nothing over replace() with the g flag beyond explicitness. Choose replace() instead when you genuinely want first-match-only semantics or when the pattern itself is a regex with captures and alternation. One habit worth keeping from replace(): the replacement string still honors $-patterns like $$ and $&, so dynamically supplied replacement text containing dollar signs still needs care or a function replacer.

⚠️ Common Mistakes

Passing a regular expression without the global flag: replaceAll() throws a TypeError for a non-global regex rather than quietly replacing once. The rule is simple: string patterns need nothing, regex patterns must carry the g flag.

Assuming the replacement string is inserted verbatim: the $-patterns of replace() still apply, so $$ collapses to a single dollar sign and $& reinserts the match. Replacing into prices, or splicing in user-provided replacement text, can corrupt output; escape dollars or use a function replacer.

Forgetting environment support: replaceAll() is ES2021, so very old browsers and Node versions before 15 lack it, and calling it there throws at runtime. Transpilers do not polyfill methods, only syntax, so a polyfill or a target check is needed for legacy support.

Using it as a statement and discarding the result: like every string method it returns a new string; phone.replaceAll(' ', '') without an assignment changes nothing.

Chaining many replaceAll() calls where one pass would do: each call rescans and reallocates the entire string. Four chained single-character removals over large input do four full passes that a single regex character class with replace() handles in one.

Reaching for replaceAll() to strip whole categories of characters: removing 'everything that is not a digit' is a character-class job for replace() with a global regex, not a chain of literal replaceAll() calls that inevitably misses characters you did not anticipate.

✅ Best Practices

Make replaceAll() the default for literal, every-occurrence substitution; the name states the semantics and eliminates the missing-g-flag class of bugs entirely.

Feed user-supplied search text to replaceAll() as a plain string instead of building a RegExp from it, which removes the need for metacharacter escaping and the injection risks that come with it.

Still treat the replacement side carefully: double any literal dollar signs or use a replacer function when replacement text is dynamic.

Prefer one regex pass over a long replaceAll() chain when removing several unrelated characters from large strings, using a character class or alternation to fuse the work.

Replace the legacy split-join idiom with replaceAll() during refactoring; it is clearer, avoids the intermediate array, and behaves identically for literal patterns.

Check your runtime floor before adopting it in library code; when ES2021 cannot be assumed, replace() with an escaped global regex remains the portable equivalent.

⚡ Performance Notes

replaceAll() makes one pass over the string, so its cost scales with the input length and the number of matches, and each call allocates one new result string. With a string pattern it uses plain substring search with no regex compilation, making it at least as fast as the equivalent global regex and faster than the old split-join idiom, which builds a throwaway array of fragments. The trap is the chain: cleaning input with five successive replaceAll() calls performs five full scans and five allocations, so on large strings or hot paths, fuse the work into a single regex character class or alternation with replace(), or a single function-replacer pass with a lookup map. For typical form-input cleanup the difference is irrelevant, and the readable chain is fine; measure before optimizing, but know that pass count, not the method itself, is where the time goes.

🌍 Real World Example

Data Cleaning and Text Normalization

Three cleanup utilities. cleanPhoneNumber() strips spaces, hyphens, and parentheses from user-entered phone numbers through a readable chain of literal replaceAll() calls, producing bare digits for storage; no regex escaping is needed even though parentheses are regex metacharacters, which is exactly the ergonomic win of string patterns. normalizeLineEndings() converts Windows CRLF and old Mac CR line endings to Unix newlines, ordering the two replacements so the CRLF pair is handled before lone carriage returns. escapeMarkdown() prefixes each Markdown control character with a backslash so user text can be embedded in Markdown output without triggering formatting.

// Clean up phone number input
function cleanPhoneNumber(phone) {
  return phone
    .replaceAll(' ', '')
    .replaceAll('-', '')
    .replaceAll('(', '')
    .replaceAll(')', '');
}

console.log(cleanPhoneNumber('(010) 1234-5678'));
// Output: '01012345678'

// Normalize line endings across platforms
function normalizeLineEndings(text) {
  return text
    .replaceAll('\r\n', '\n')  // Windows to Unix
    .replaceAll('\r', '\n');     // Old Mac to Unix
}

// Escape markdown special characters
function escapeMarkdown(text) {
  return text
    .replaceAll('*', '\\*')
    .replaceAll('_', '\\_')
    .replaceAll('~', '\\~')
    .replaceAll('`', '\\`')
    .replaceAll('#', '\\#');
}

console.log(escapeMarkdown('Hello *world* and _universe_'));
// Output: 'Hello \*world\* and \_universe\_'

// Replace placeholder tokens in content
function fillTokens(content, tokens) {
  let result = content;
  for (const [key, value] of Object.entries(tokens)) {
    result = result.replaceAll(`{{${key}}}`, value);
  }
  return result;
}

const template = 'Welcome {{user}}! Your order #{{orderId}} is ready.';
console.log(fillTokens(template, { user: 'Alice', orderId: '12345' }));
// Output: 'Welcome Alice! Your order #12345 is ready.'

Related Methods