2

I was playing with .replace() recently and found the following behaviour odd. Take the two following code snippets:

const str = "Hello world";
const res = str.replace(/(o)/g, "$1".repeat(3));
console.log(res); // Hellooo wooorld (which I expected)

The above print "Hellooo wooorld", which I expected, as I am using .repeat(3) on the matched o characters.

However, when I apply the same logic and use .toUpperCase(), my string remains unchanged:

const str = "Hello world";
const res = str.replace(/(o)/g, "$1".toUpperCase());
console.log(res); // Hello world (expected HellO wOrld)

The above, to my surprise, didn't work as it printed the original string and not "HellO wOrld". So, why does the first code snippet work but the second doesn't?. I am aware that I can use the replacement function for this, but I am more concerned about understanding why the first snippet works, and the second doesn't.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
  • 5
    `"$1".toUpperCase()` is still `"$1"`. `"$1".repeat(3)` is `"$1$1$1"`. You pass these strings to the function, not the method calls. – Sebastian Simon Aug 10 '19 at 13:00

1 Answers1

2

The expression that the second argument gets evaluated to will replace all occurrences of $#-like strings in the passed argument. In the first code, the passed argument is '$1$1$1':

const res = str.replace(/(o)/g, "$1".repeat(3));
// interpreter first parses the expression in the second parameter,
// so it knows what to pass to replace:
const res = str.replace(/(o)/g, "$1$1$1");
// THEN the function call occurs

In the second code, calling toUpperCase on '$1' results in the same string, $1:

const res = str.replace(/(o)/g, "$1".toUpperCase());
// interpreter first parses the expression in the second parameter,
// so it knows what to pass to replace:
const res = str.replace(/(o)/g, "$1");
// THEN the function call occurs
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320