A catalogue editor enters a new label containing a dollar sign. The saved preview unexpectedly repeats the old label. Nothing was wrong with the stored text: the replacement operation interpreted part of that text as an instruction.
The short answer is that an ordinary JavaScript replacement string has a small substitution language. A replacement callback follows a different path: its returned text is converted to a string and inserted without a second pass through that substitution language. The distinction matters whenever a website inserts supplied text into an existing sentence, identifier or preview.
This lesson follows original, deliberately small examples. It assumes built-in string and regular-expression replacement, with ordinary matchers. Custom replacement hooks can implement another contract. Literal insertion here describes replacement semantics; it does not establish that text is suitable for every later HTML, URL or application context.
This specialist guide belongs to the Websites root. It also connects to The Gold Standard of Education | Learning That Transfers into Life and the How X Works hub. The worked cases are original teaching examples; their numbers are stipulated so that the reasoning can be checked.
eduKateSG · Websites
Find your next learning step
Follow replacement templates and literal callback results. Work dollar tokens, capture references, exact output text and deliberate all-occurrence changes.
ROUTE 1 · CHAPTERS 1–3
Locate the changed meaning
Separate supplied text, selected match and template construction.
ROUTE 2 · CHAPTERS 4–6
Read substitution tokens
Trace numbered and named captures plus copied source context.
ROUTE 3 · CHAPTERS 7–9
Choose literal insertion
Follow callback results, argument positions and match counts.
ROUTE 4 · CHAPTERS 10–12
Transfer and check
Respect synchronous return values and verify changed archive examples.
ROUTE 5 · CHAPTERS 13–14
Repair and explain
Preserve the intended label and report the exact construction.
Chapter contents
Locate the changed meaning · Chapters 1–3
1. Begin with the text the editor intended to preserve
Read substitution tokens · Chapters 4–6
4. Follow numbered captures rather than guessed labels
Choose literal insertion · Chapters 7–9
7. Use a callback to preserve supplied text literally
8. Read callback arguments before building a transformation
9. Change the number of matches without changing insertion meaning
Transfer and check · Chapters 10–12
10. Do not mistake callback return values for asynchronous work
11. Transfer the reasoning to a changed archive label
12. Build checks that distinguish the competing explanations
Repair and explain · Chapters 13–14
CHAPTER 1 OF 14 · Locate the changed meaning
1. Begin with the text the editor intended to preserve
Imagine a fictional exhibition catalogue. Its preview line reads “Item A17 is ready”. An editor wants to replace A17 with a supplied label. The new label is the four-character sequence dollar, ampersand, hyphen, X. Written as JavaScript source, that value is "$&-X". The intended preview is “Item $&-X is ready”, with the dollar and ampersand visible as data.
Calling the built-in string replacement method with that value as its second argument produces “Item A17-X is ready”. The matched text A17 has returned. The operation has recognised dollar-ampersand as a substitution token meaning the complete match. That interpretation occurs even though the supplied label did not come from a regular expression.
const line = "Item A17 is ready";
const supplied = "$&-X";
line.replace("A17", supplied);
// "Item A17-X is ready"
line.replace("A17", () => supplied);
// "Item $&-X is ready"
Keep three records separate: the original line, the supplied label, and the produced preview. The supplied variable still contains the original four characters. The source line has not been mutated. A newly returned string differs because the replacement operation assigned a special meaning to part of the second argument.
This gives us a precise debugging question. Was the editor's text already wrong before replacement, or did the operation reinterpret it? Logging only the final preview cannot answer that question. A controlled fixture containing a dollar sign makes the distinction visible without requiring any real catalogue data.
The first repair is therefore conceptual: decide whether the second argument is meant to be an authored template or literal supplied text. Both are useful jobs. They require different explanations and different checks. Merely adding more punctuation to the supplied value, or removing dollar signs from legitimate labels, conceals the boundary rather than defining it.
CHAPTER 2 OF 14 · Locate the changed meaning
2. Separate matching from construction of the result
Replacement has two linked responsibilities. It identifies a matching span in the original string, then constructs output around that span. Understanding the first responsibility does not automatically explain the second. A regular expression may locate exactly the intended characters while a replacement template still produces unexpected text.
For the ordinary string search in our first example, the match begins after “Item ” and has length three. The untouched prefix is “Item ”. The untouched suffix is “ is ready”. The method inserts its calculated replacement between those two pieces. It returns a new string containing that arrangement.
Now change only the second argument to "B29". There are no recognised substitution sequences in this replacement text, so its calculated replacement is B29. The result is the expected “Item B29 is ready”. This ordinary case is useful, but it does not distinguish template processing from literal insertion. Both paths happen to agree.
A good comparison uses a value on which the paths disagree, such as our dollar-ampersand label. With the supplied string, substitution produces A17-X. With a callback returning the same supplied value, insertion produces the literal dollar-ampersand sequence. The match and surrounding text remain identical across the comparison.
For learners, draw the original line as three cards: prefix, matched span and suffix. Put a fourth card beside them for the replacement argument. Ask what rule converts that argument into the inserted piece. This keeps the explanation grounded in a visible operation rather than a vague claim that JavaScript “changes dollar signs”.
There are also separate questions about how many spans are selected. A plain string search passed to replace selects its first occurrence. A global regular expression can select several. Changing match selection does not remove the template interpretation of an ordinary string replacement. We will vary that condition later, after the construction rule is stable.
CHAPTER 3 OF 14 · Locate the changed meaning
3. Read the whole-match and literal-dollar tokens
Two tokens explain many surprising previews. Dollar-ampersand inserts the complete matched substring. Two consecutive dollar signs insert one literal dollar sign. The second rule lets an author deliberately write dollar text inside a replacement template, but it is another interpretation rule rather than a promise to preserve the argument byte for byte.
Take the source "A17" and the replacement template "[$&] $$". The bracket characters are ordinary text. Dollar-ampersand contributes A17. The space remains. The doubled dollar contributes one dollar. The complete result is [A17] $. Work those pieces in order before running the expression.
"A17".replace("A17", "[$&] $$");
// "[A17] $"
"A17".replace("A17", () => "[$&] $$");
// "[$&] $$"
The callback case preserves both dollar pairs as returned text. It does not reinterpret the returned dollar-ampersand, and it does not collapse the returned double dollar. This is why the same visible string can be an instruction in one position and ordinary output in another.
Do not describe double dollar as a general-purpose escape for every language. It has this defined role in JavaScript replacement templates. A later template engine, shell, regular-expression pattern or HTML parser has its own rules. The correct escaping or insertion strategy depends on the next consumer, not merely on the presence of a punctuation character.
There is a useful test of understanding here. Suppose the editor intentionally wants the authored template to surround every matched identifier with brackets. Dollar-ampersand is then doing exactly the desired work. Replacing every string argument with a literal callback would change that feature. The goal is not to abolish templates; it is to choose them deliberately.
For a supplied free-text label, literal preservation is usually the stated requirement of our exercise. For an authored formatting rule, substitution can be the requirement. Write that distinction beside the fixture so a later maintainer does not “repair” the chosen behaviour in the opposite direction.
CHAPTER 4 OF 14 · Read substitution tokens
4. Follow numbered captures rather than guessed labels
A regular expression can capture smaller pieces within its complete match. In the expression /([A-Z])(\d+)/, the first pair of capturing parentheses retains the letter, while the second retains the digits. Matching A17 therefore provides the complete match A17, capture one A and capture two 17.
Use the replacement template "$2-$1". The first token contributes the second capture, 17. The hyphen is ordinary text. The final token contributes A. The result is 17-A. Nothing in this rule means “second word” or “second field in the eventual record”. Capture numbering follows the pattern's capturing groups.
"A17".replace(/([A-Z])(\d+)/, "$2-$1");
// "17-A"
"A17".replace(/([A-Z])(\d+)/, () => "$2-$1");
// "$2-$1"
Now change the pattern to use a noncapturing group for the letter: /(?:[A-Z])(\d+)/. Only the digits are captured. A template using capture one now inserts 17. This is a changed pattern contract, not a changed value in the original source. A seemingly harmless parentheses edit can therefore alter template meaning.
There is another distinction between a capture that exists but did not participate and a capture number that does not exist. With /(A)?B/ matching B, the first capture exists and is undefined because its optional part did not match. Its replacement contribution is empty text. With /B/, there is no first capture, so a token referring to capture one does not acquire an imaginary empty group.
These cases deserve independent fixtures. Reporting both as “no capture” hides the reason they produce different output. In a practical change, keep pattern structure and replacement structure under the same review. If either changes, replay cases involving optional groups and literal dollar text, as well as the ordinary successful capture.
CHAPTER 5 OF 14 · Read substitution tokens
5. Keep named captures and missing captures distinct
Named captures can make an authored transformation easier to read. Our fictional identifier pattern can name its two pieces letter and digits. A replacement template can then refer to those names rather than positional numbers. The names belong to the pattern's capture record; they are not automatically drawn from variables in the surrounding program.
const pattern = /(?<letter>[A-Z])(?<digits>\d+)/;
"A17".replace(pattern, "$<digits>-$<letter>");
// "17-A"
Changing a JavaScript variable called digits does not change what this template token selects. Changing the capture name inside the pattern can. This separation helps a learner avoid treating every dollar-prefixed expression as JavaScript interpolation. Replacement templates are their own small language, with a limited vocabulary.
When the matcher supplies a named-capture record, a reference to a missing name contributes empty text under the ordinary substitution rules. When no named-capture record is supplied at all, the same apparent named-token spelling is not resolved through an invented record. These are different starting conditions, so test them separately rather than relying on a broad slogan about “missing names”.
Numbered references have an additional reading wrinkle when two digits follow the dollar. The substitution algorithm considers the available capture count. A two-digit candidate can fall back to a valid first digit followed by an ordinary remaining digit. For example, with one capture containing A, a template written as dollar-one-zero can contribute A followed by 0. It does not establish that a tenth capture exists.
For most practical formatting, use clearly named captures when they improve the contract, or a callback that constructs the desired string explicitly. Neither choice excuses a pattern change from testing. A callback can still use the wrong argument or preserve the wrong capture.
The checking habit is to record the complete match, capture positions or names, and each intended output piece. Once that record is explicit, a surprising result can be traced to a particular reference instead of being blamed on all regular expressions at once.
CHAPTER 6 OF 14 · Read substitution tokens
6. Explain why prefix and suffix tokens can duplicate text
Replacement templates also have tokens for the original text before and after a match. Those tokens can appear surprising because the replacement method already preserves the ordinary prefix and suffix around the replacement. Asking for either piece inside the inserted replacement adds another copy there.
Consider the original source "L-A17-R". Its complete match is A17. The ordinary untouched prefix is "L-", and its untouched suffix is "-R". If the replacement template requests the original prefix, the final construction contains the normal prefix, then the requested extra prefix, then the normal suffix. The final text is "L-L--R".
"L-A17-R".replace("A17", "$`");
// "L-L--R"
"L-A17-R".replace("A17", "$'");
// "L--R-R"
In the second expression, the inserted piece is the original suffix. The final output therefore contains one normal prefix followed by two copies of that suffix. The method has not moved its match boundary or accidentally processed the source twice. It has followed the template while constructing the surrounding result normally.
These tokens refer to the original input string for the match. Do not model a global replacement as repeatedly editing a progressively changed source and then deriving later prefixes from that edited text. That mental model can predict the wrong lengths and the wrong copied content.
The distinction matters for generated previews that can become unexpectedly long. A short authored template can request substantial surrounding text for multiple matches. Our classroom examples do not establish an allocation bound or performance guarantee. They show why output length should be checked against the actual transformation when a feature accepts such templates.
For learner practice, write the three construction pieces before joining them. Label a copied prefix as a requested contribution inside the replacement, not as the ordinary outer prefix. That small label prevents the common mistake of counting it once when the final result necessarily contains it twice.
CHAPTER 7 OF 14 · Choose literal insertion
7. Use a callback to preserve supplied text literally
For the catalogue's free-text label requirement, a callback can return the supplied string without requesting replacement-template interpretation. The function is called when a match is selected. Its returned value becomes the inserted string under the ordinary conversion rule. Dollar sequences inside that returned string remain characters in the inserted result.
This is not the same as returning a replacement template and asking JavaScript to process it again. A callback returning dollar-ampersand produces dollar-ampersand. Returning two dollar signs produces two dollar signs. Returning a named-capture-looking sequence leaves that spelling in the inserted output.
function putLiteralLabel(line, oldLabel, newLabel) {
return line.replace(oldLabel, () => newLabel);
}
putLiteralLabel("Item A17 is ready", "A17", "$&-X");
// "Item $&-X is ready"
Our helper assumes string inputs and a first-occurrence replacement requirement. It is intentionally small. It does not validate catalogue identifiers, select all occurrences, authorise an edit or decide how the resulting text is later rendered. Those decisions belong to the surrounding feature's contract.
Be precise about “literal”. The returned text is literal with respect to the replacement-template language. If a program subsequently treats the result as HTML, another interpretation boundary exists. If it writes into a text-only DOM property, the destination has a different role. A statement about the replacement method alone cannot certify every later use.
The callback also provides a useful place to state transformation intent. A named function such as one returning a chosen label can make it clear that dollar punctuation is data. This can be easier to maintain than a chain that manually doubles dollar signs, particularly when the text passes through several independently authored transformations.
Test the helper with ordinary letters and with token-looking strings. The ordinary case establishes that basic replacement works. The dollar cases establish the distinction that motivated the helper. Keep both: a repair that protects punctuation should still replace the intended old label in the ordinary case.
CHAPTER 8 OF 14 · Choose literal insertion
8. Read callback arguments before building a transformation
A callback need not return fixed supplied text. It can use the matched substring, captured values, match position and original input to construct a deliberate result. This is a separate construction mechanism from a string template, even when both can express the same simple rearrangement.
For our two-capture identifier, a callback receives the complete match first, then capture one, then capture two, followed by the position and original string. A callback that returns digits, a slash and letter produces 17/A for A17. Name the arguments according to the pattern so that their relationship remains visible.
"A17 B29".replace(/([A-Z])(\d+)/g,
(whole, letter, digits, offset) => `${digits}/${letter}@${offset}`);
// "17/A@0 29/B@4"
The template literal inside this callback is JavaScript string construction. Its interpolation syntax is evaluated by the function. That does not turn its final returned string into a replacement template. Distinguish the language used to produce the return value from the language, if any, that later consumes it.
When named captures exist, a groups object is an additional callback argument after the original string. A generic callback that locates the offset by counting arguments can break if it assumes the same ending positions for named and unnamed patterns. In a focused feature, an explicit signature matched to a known pattern is often easier to explain and test.
Offsets also have a measurement basis. JavaScript string positions are UTF-16 code-unit positions. They are not guaranteed to equal visible-character counts or UTF-8 byte offsets. An emoji before A17 can shift the reported position by two code units while appearing as one visible symbol. The existing text-count guide develops that boundary in depth.
For this lesson, keep offsets as evidence of where matching occurred. Do not reuse them as a cursor position or external byte location without checking the destination's unit. Correct capture construction and correct position interpretation are related responsibilities, but one does not establish the other.
CHAPTER 9 OF 14 · Choose literal insertion
9. Change the number of matches without changing insertion meaning
The catalogue editor now wants to replace every occurrence of a literal marker. With source "A17 / A17", ordinary replace with the string search "A17" changes only the first occurrence. A callback does not make the search global. Its role is to determine the replacement text for each match actually selected.
For a literal all-occurrences requirement, the built-in replaceAll method can take a string search. Returning the supplied label from a callback preserves its replacement punctuation across the selected occurrences. In our fixture, a supplied value of dollar-ampersand yields "$& / $&", with both markers replaced literally.
const supplied = "$&";
"A17 / A17".replaceAll("A17", () => supplied);
// "$& / $&"
"A17 / A17".replaceAll("A17", supplied);
// "A17 / A17"
The second line appears unchanged because the replacement template requests the complete match at each occurrence. Unchanged output therefore does not prove that no matching occurred. A callback counter or a controlled token-changing template can distinguish “no match” from “matched and reconstructed the same text”.
A regular expression supplied to replaceAll must have the appropriate global flag under the built-in contract. That requirement differs from string replaceAll and from non-global replace. Keep the search object's kind and flags in the test record rather than referring vaguely to “replace all”.
Newly inserted marker-looking text is not automatically searched again within the same ordinary operation. If the callback returns A17-X, the A17 within that returned text does not cause an endless replacement loop. A separately invoked later replacement can process it, but that is another operation with another input.
This is a useful changed condition to teach explicitly. First decide match selection: first, all literal occurrences, or selected pattern matches. Then decide insertion: authored substitution template or callback result. Treating these as two independent choices makes both the implementation and the explanation easier to check.
CHAPTER 10 OF 14 · Transfer and check
10. Do not mistake callback return values for asynchronous work
The ordinary replacement callback is synchronous. If it returns a number, that value is converted to a string for insertion. If it falls through without returning, the resulting undefined value is converted too. That is different from some callback contracts where undefined means omission or deletion.
An async function returns a promise immediately. Built-in replacement does not wait for that promise to settle and then insert its eventual value. For an ordinary promise object, string conversion commonly produces the familiar promise tag. The exact issue is the immediate returned object, not a delayed replacement that is merely running slowly.
"A17".replace("A17", () => undefined);
// "undefined"
"A17".replace("A17", async () => "B29");
// "[object Promise]"
These examples are especially helpful alongside the JSON reviver lesson. Returning undefined from a reviver can request deletion at a position. Returning undefined from this replacement callback has another meaning. A callback's return value only makes sense within the calling operation's contract.
If labels need asynchronous lookup, a feature needs an explicit sequence that obtains the required values and then constructs text under a stated match policy. It should also define failure handling, ordering and whether a later result may update the current view. Simply adding async to the existing callback does not create that sequence.
There can be effects even when the final operation fails. A callback can update a counter, write to an external record or throw an exception. A thrown error prevents a normal replacement result from being returned, but it does not automatically reverse earlier external effects. Use isolated fixtures when testing this behaviour.
For our catalogue feature, the clean requirement remains modest: take already available string labels and produce a new preview string. Keep asynchronous service work outside this small helper. That makes a failing fixture about insertion semantics easier to understand and avoids implying that a string API supplies a complete import or request lifecycle.
A callback can also return an object whose string conversion performs work. For a controlled example, return an object with a toString method that records one marker and returns B29. The inserted text can be B29 while the marker establishes that conversion occurred. This does not mean replacement interpreted B29 as a template; it means obtaining the inserted string was itself an active step. A throwing conversion prevents a normal result just as a throwing callback does, while earlier outside effects can remain.
Keep custom search objects outside the ordinary fixtures. JavaScript can delegate replacement through a supplied object's Symbol.replace method. Such an object can return a deliberately different result without following the built-in template algorithm discussed here. If a real helper receives a custom search object, inspect that actual hook before treating this lesson's built-in trace as its implementation. Naming the assumption is more useful than describing an observed difference as a browser inconsistency.
There is a final conversion boundary before matching as well. A supplied object used where a search string or replacement string is expected can be converted according to the relevant method's order. Our feature narrows inputs to already available strings so that label preservation has one clear meaning. A wrapper may reject other types explicitly rather than allowing surprising conversion, but that is a wrapper policy. Tests should distinguish a rejected input from a successfully converted one and a successfully converted input from an accepted catalogue record.
These extensions help locate a failure without enlarging the simple helper's promise. Ask whether the callback ran, whether its value became a string, whether a normal result returned and which outside markers were already recorded. The sequence explains partial effects more accurately than saying the entire replacement either happened or did not happen.
CHAPTER 11 OF 14 · Transfer and check
11. Transfer the reasoning to a changed archive label
Now use a fictional archive rather than the exhibition catalogue. The source line is "Archive Q42; shelf Q42". The editor supplies the label "$1:$&:$$". The requirement is to replace both literal Q42 markers with exactly that label. Before running code, write the intended complete output, including every dollar sign.
Under this literal requirement, the expected result is "Archive $1:$&:$$; shelf $1:$&:$$". A string-search replaceAll callback returning the supplied label meets this stated transformation. A replacement string does not: the whole-match and doubled-dollar tokens are interpreted, while the numbered-capture-looking part has no capture supplied by the string search.
Change the requirement again. The archive now wants authored identifier rearrangement using a pattern that captures the letter and digits. A template requesting capture two, a slash and capture one intentionally produces 42/Q. Literal insertion of that template would preserve token spellings and fail the new job.
The letters and numbers have changed, but the decisive transfer is the change of intent. The learner must identify whether the second argument is data or a formatting instruction. Memorising “always use a callback” does not demonstrate that distinction when an authored template is actually desired.
Add one more condition: the original source has no Q42 occurrence. Both ordinary paths return the unchanged source in this simple fixture. No matching callback is called. That result does not contradict the earlier difference; it means the operation never reached an insertion decision for that input.
Finally, put an emoji before the archive identifier and ask for a callback offset. The matched content and literal label policy remain unchanged, while the code-unit position changes. This extension checks whether the learner can preserve one established rule while revising a different measurement assumption. A strong explanation names which condition changed and which part of the earlier reasoning still applies.
CHAPTER 12 OF 14 · Transfer and check
12. Build checks that distinguish the competing explanations
A useful check set should make plausible wrong explanations disagree with the expected result. An ordinary replacement from A17 to B29 is necessary but insufficient. It cannot reveal whether a helper interprets dollar tokens. Include supplied dollar-ampersand, double-dollar and numbered-capture-looking labels, and assert exact resulting strings.
Separate string search from regular-expression search. With a string search, verify that an absent capture token stays under the no-capture rule. With a known capturing pattern, verify numbered rearrangement. Then test an optional nonparticipating capture separately from a capture number that does not exist. These fixtures establish different conditions.
Check surrounding context too. A source containing a prefix and suffix should reveal whether a template copies either into the inserted piece. Assert the whole output rather than merely looking for the new label somewhere within it. A duplicated suffix can coexist with the expected label, so a weak containment check can pass despite the bug.
For the callback path, record invocation count and relevant arguments. Test first-occurrence replacement, all-occurrences replacement, no match, and an input whose visible symbols differ from its code-unit positions. Keep callbacks free from unnecessary outside effects so the observed string remains the main evidence.
Add controlled return-value cases: a number, undefined and an ordinary async callback. The expected immediate result should be explicit. If an application rejects such return types before replacement, test that wrapper policy separately; do not attribute its restriction to the built-in method.
Fresh inputs matter. A reused stateful matcher or a callback closing over changing state can introduce a different question. The related lastIndex article explains matcher state. In this lesson, keep that state ordinary and declared unless it is the condition being tested.
Passing these checks establishes the specified replacement behaviour in the tested runtime. It does not prove that every downstream display, storage format or service rule accepts the result. A useful report preserves that boundary while still giving a clear answer about the original punctuation failure.
CHAPTER 13 OF 14 · Repair and explain
13. Repair a feature without erasing legitimate editor text
Suppose a preview helper currently accepts a supplied label as a replacement string. The observed failure is that dollar-ampersand becomes the old identifier. A focused repair can change insertion to a callback returning that supplied string while retaining the established match-selection rule. Test that precise change with the failing label and an ordinary one.
Do not silently broaden first-occurrence replacement into all-occurrences replacement during the same repair unless that is the actual requirement. A catalogue line may contain an identifier in a descriptive note that should remain untouched. Matching scope and insertion semantics need separate acceptance criteria even when one line of code can change both.
Likewise, do not strip dollar signs from input merely to avoid their template role. Dollar punctuation can be legitimate data. A restriction might be part of a specific identifier grammar, but that should be an independently justified rule with a comprehensible message. It is not a substitute for correct literal insertion.
Preserve the original submitted label during diagnosis and allow correction if a wider field rule fails. A preview should not quietly rewrite a person's intended text and then present the rewrite as though it were the original. The application can maintain a derived display string while retaining the source needed to explain its transformation.
For an authored-template feature, take the opposite care. Keep the documented tokens, show representative examples, and test capture changes against existing templates. Switching to literal insertion would remove a capability users deliberately rely on. A good repair follows the feature's promise rather than a universal preference for one API path.
After changing the helper, inspect the actual returned value and its intended rendered destination. Keep publication, permissions and service outcomes outside the helper's success claim. The operation establishes a string transformation; the surrounding journey must still establish that the right record received the right accepted edit.
CHAPTER 14 OF 14 · Repair and explain
14. Explain the result through a short construction ledger
When reporting a replacement result, name the input, selected match, replacement mode and final text. If captures matter, show the capture record. If surrounding-text tokens matter, show the original prefix and suffix. If a callback matters, distinguish its immediate returned value from any later asynchronous outcome.
For the first catalogue failure, the explanation can be short and complete. The editor supplied dollar-ampersand-hyphen-X as literal data. The helper passed it as a replacement template. Dollar-ampersand requested the matched A17, so the returned preview contained A17-X. Returning the supplied string from a callback preserved the intended punctuation under the same first-match rule.
That explanation locates the first changed meaning. It does not claim that the stored label was corrupted, that the matcher chose the wrong span, or that all dollar signs are dangerous. Each of those would describe another problem requiring other evidence.
A learner can check independence by solving the archive case without copying the original code. Ask for an exact predicted string, then ask what changes if the requirement becomes an authored capture rearrangement. The explanation should follow the requirement and pattern, not just recall a preferred callback spelling.
For practical work, retain a few small fixtures with readable expected outputs. They are easier to review than a large preview screenshot in which extra copied text can hide. Include a fixture that failed before the repair and one that protects ordinary behaviour afterwards.
The lasting skill is recognising an interpretation boundary. A sequence can be supplied data, an authored template or already constructed output. JavaScript replacement assigns different rules at those positions. Once the positions are explicit, a website can preserve an editor's text faithfully, use formatting tokens deliberately, and explain the exact transformation without extending the claim beyond what was checked.
Continue through the verified reading route
Tracing Regular-Expression Matches When lastIndex Carries Across Calls
Tracing Regular-Expression Matches When lastIndex Carries Across Calls. Pattern state and matching positions have a different contract from construction of replacement text.
Counting Form Text Without Confusing Characters, Bytes and Grapheme Clusters
Counting Form Text Without Confusing Characters, Bytes and Grapheme Clusters. Callback offsets use UTF-16 positions; visible text units and byte counts need their own account.
Tracing JSON Revivers from Child Values to the Final Root
Tracing JSON Revivers from Child Values to the Final Root. Returning undefined means deletion in ordinary reviver processing; replacement callbacks interpret their return values differently.
Compare replacement construction with captured split output. The same authored capture structure can affect another operation’s result in a different way: split can insert captured separators into its returned array.
Separate assembly, pattern input and replacement output
Follow String.raw literal segments and substitution conversion when first constructing text. For a literal search term, prepare the regular-expression fragment before matching; the replacement caption still follows its own output contract.
Frequently asked questions
Does a string search disable replacement tokens?
No. Ordinary replacement-string processing still recognises tokens such as dollar-ampersand and double dollar. A string search simply does not supply regular-expression capture groups.
Are dollar tokens interpreted in a callback's returned string?
The ordinary built-in replacement path inserts the callback's converted return value without another substitution-template pass.
Does a callback make replace change every occurrence?
No. Match selection is separate. A string search with replace selects its first occurrence; choose the appropriate all-occurrences contract when that is required.
Is an unmatched optional capture the same as a missing group?
No. A defined capture that did not participate and a capture number absent from the pattern begin under different substitution conditions.
Can an async callback supply a label later?
Built-in replacement does not await the callback's promise. Obtain asynchronous values through an explicit surrounding workflow before constructing the intended string.
Does literal replacement make a result safe for every destination?
No. Literal here concerns replacement-template interpretation. A later HTML, URL, storage or service boundary has its own requirements.
Authoritative sources and further reading
ECMAScript: String replace. The built-in string-search path and callback versus template construction.
ECMAScript: GetSubstitution. Whole-match, dollar, numbered, named and source-context token rules.
ECMAScript: regular-expression replacement. Pattern capture records and replacement callback arguments.
Mozilla: String replace. An implementation-facing reference for replacement strings and callback results.
Return to the Websites subject guide, The Gold Standard of Education, or the How X Works hub.