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
A new string with replacements made
Examples
const str = 'Hello World';
console.log(str.replace('World', 'JavaScript'));
console.log(str.replace(/o/g, '0')); 📌 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 = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, char => escapeMap[char]);
}
console.log(escapeHtml('<script>alert("xss")</script>'));
// Output: '<script>alert("xss")</script>'
// 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'