replace()

ES3+

Returns a new string in which a pattern has been replaced: with a string pattern or a regular expression lacking the global flag, only the first match is replaced, while a regex with the g flag replaces every match. The replacement can be a literal string, which supports special $-patterns, or a function called for each match. The original string is never modified.

Syntax

string.replace(searchValue, replaceValue)

Parameters

searchValue string | RegExp

The value to search for

replaceValue string | Function

The replacement string or function

Return Value

string

A new string with replacements made

Examples

JavaScript
const str = 'Hello World';
console.log(str.replace('World', 'JavaScript'));
console.log(str.replace(/o/g, '0'));
Output:
// 'Hello JavaScript' 'Hell0 W0rld'

📌 When to Use

Use replace() for targeted text surgery: substituting template placeholders with data, escaping HTML special characters before rendering user content, converting between naming conventions like camelCase and kebab-case, redacting or masking sensitive fragments, and cleaning up formatting artifacts. It is the most powerful string transformation method because the search side accepts full regular expressions and the replacement side accepts a function, which turns replace() into a general match-and-rewrite engine: the function receives the match and its capture groups and returns whatever should stand in its place, enabling lookups, arithmetic, and conditional logic per match. Choose a plain string pattern only when you truly mean 'the first occurrence, literally'; for replace-every-occurrence with a literal string, replaceAll() states the intent directly and avoids both the classic missing-g-flag bug and the need to regex-escape dynamic search text. In replacement strings, remember the $-patterns: $1 through $99 insert capture groups, $& the whole match, and $$ a literal dollar sign, which is a genuine gotcha when the replacement text is user-supplied currency data. For merely finding or testing text, includes(), indexOf(), or regex test() are cheaper and clearer; reserve replace() for actually producing transformed output.

⚠️ Common Mistakes

Replacing only the first occurrence by accident: with a string pattern or a non-global regex, replace() stops after one match, so 'a-b-c'.replace('-', '_') yields 'a_b-c'. Replacing all occurrences requires a regex with the g flag or replaceAll(). This is the single most common replace() bug in real code.

Forgetting that special characters in a regex pattern have meaning: building a pattern from user input with new RegExp(userText) lets dots, parentheses, and plus signs act as metacharacters, causing wrong matches or syntax errors. Escape dynamic search text, or sidestep the issue entirely by using replaceAll() with a string argument.

Being bitten by $ in the replacement string: sequences like $&, $1, and even $' have special meaning, so replacing into text that contains dollar amounts, or inserting user input containing $, can garble output. Write $$ for a literal dollar sign, or use a replacer function, whose return value is inserted verbatim.

Expecting the original string to change: replace() returns the transformed copy; str.replace(...) without using the result does nothing. The immutability of strings means every transformation must be reassigned.

Confusing $1 with match numbering or using it without capture groups: $1 refers to the first parenthesized group in the pattern. If the pattern has no groups, $1 is inserted literally, and with nested groups the numbering counts opening parentheses left to right, which is easy to miscount.

Using string replacement where a replacer function is needed: when the substitute depends on the matched text, such as looking up an escape map or transforming case, a static replacement string cannot express it. The function form receives the match and its groups and computes the result per occurrence.

✅ Best Practices

Default to replaceAll() for replace-every-literal-occurrence jobs, and reserve replace() for first-only semantics or genuine regex power; the choice then documents itself.

Use the replacer-function form whenever the output depends on the match: escape maps, unit conversion, case transformation, and template substitution all become clear, testable functions.

Anchor and constrain regex patterns as tightly as possible, and prefer explicit character classes over dot-star greediness, so replacements touch exactly what you intend and nothing more.

Escape regex metacharacters in any dynamically built pattern, and treat $ in dynamically built replacement strings as equally dangerous, doubling it or switching to a function replacer.

Name your capture groups in complex patterns and reference them as $<name> in replacements; positional $1 and $2 references silently break when the pattern is later edited.

Keep an eye on chained replaces: three or four .replace() calls in a row each rescan the whole string, and can often be fused into one pass with a single alternation pattern and a function replacer using a lookup map.

⚡ Performance Notes

replace() scans until the first match for non-global patterns, or over the whole string with the g flag, and builds one new output string; cost grows with input length, match count, and pattern complexity. String patterns are cheapest since they compile no regex. When using regexes in hot paths, hoist the literal or constructed RegExp out of the loop so it compiles once, and beware of catastrophic backtracking: nested quantifiers over user input can make a single replace() take seconds, a genuine denial-of-service vector. A chain of several replace() calls makes a full pass and a full allocation per link, so fusing them into one alternation with a function replacer roughly divides the work by the chain length. Replacer functions add a call per match, which is normally trivial but measurable at hundreds of thousands of matches; a static replacement string avoids that overhead when no per-match logic is needed.

🌍 Real World Example

Template Processing and Text Transformation

Three transformation patterns. processTemplate() replaces every double-brace placeholder with a value from a data object, using a global regex and a replacer function that falls back to leaving unknown placeholders intact, the essence of every template engine. escapeHtml() maps the five HTML-dangerous characters through an escape table via a character-class regex and function replacer, the standard defense against cross-site scripting when inserting user text into markup. toKebabCase() uses capture groups to find each lowercase-to-uppercase boundary, inserts a hyphen between them with $1-$2, and lowercases the result, turning camelCase identifiers into CSS-friendly kebab-case.

// Simple template variable replacement
function processTemplate(template, data) {
  return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
    return data[key] !== undefined ? data[key] : match;
  });
}

const template = 'Hello, {{name}}! You have {{count}} messages.';
const data = { name: 'John', count: 5 };
console.log(processTemplate(template, data));
// Output: 'Hello, John! You have 5 messages.'

// Sanitize HTML to prevent XSS
function escapeHtml(text) {
  const escapeMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  return text.replace(/[&<>"']/g, char => escapeMap[char]);
}

console.log(escapeHtml('<script>alert("xss")</script>'));
// Output: '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'

// Convert camelCase to kebab-case
function toKebabCase(str) {
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

console.log(toKebabCase('backgroundColor')); // 'background-color'

Related Methods