JavaScript Why does string interpolation for single $ and double $$ have same result in replace function?

Viewed 329

I'm trying to replace some code in js using template literals and came across this anomaly. Could someone explain why the below replacement produces the same output. I've tested it in Chrome(ver.92.0.4515.107) and FireFox too with the same result in the console. Is there something more to template literals.

console.log("word".replace("word", `${"$$test"}`));
//outputs : $test

console.log("word".replace("word", `${"$test"}`));
//outputs : $test

console.log(`${"$$test"}`) // direct console outputs the right value
//$$test

4 Answers

This has nothing to do with template literals. You'll see the same result if you use ordinary strings. It's because of the way the .replace() method performs its substitution.

$ has special meaning in the replacement string. The most common use is to interpolate a capture group when replacing with a regular expression, but the special processing is done even when replacing a fixed string.

$$ is the way you escape the $ so that it inserts a $, which is why $$test puts $test in the replacement.

$test does the same thing because $t has no special meaning, so it's treated literally.

It's the replacement string (by design). See MDN. The (special replacement) pattern $$ is replaced by $

For anyone who's facing this issue in the future, below is a possible solution. Used replacer function and regex to avoid pattern matching replacement. Although an escape character of some sort would do the job better.

var result = "word".replace("word",
          `${"$$test$$$"}`
            .replaceAll(/(?<=\$)[\$]+/g, x => "$".repeat(x.length * 2)));
console.log(result);

//example
console.log("<span id='tabid' [tabpage=$$navliID]></span>".replace("[tabpage=$$navliID]", `tabpage='${"$$navli$$$"}'`.replaceAll(/(?<=\$)[\$]+/g, x => "$".repeat(x.length * 2))));     
Related