I can see three ways around this:
-
Use template strings like they were designed to be used, without any
format
function:console.log(`Hello, ${"world"}. This is a ${"test"}`); // might make more sense with variables: var p0 = "world", p1 = "test"; console.log(`Hello, ${p0}. This is a ${p1}`);
or even function parameters for actual deferral of the evaluation:
const welcome = (p0, p1) => `Hello, ${p0}. This is a ${p1}`; console.log(welcome("world", "test"));
-
Don’t use a template string, but a plain string literal:
String.prototype.format = function() { var args = arguments; return this.replace(/\$\{p(\d)\}/g, function(match, id) { return args[id]; }); }; console.log("Hello, ${p0}. This is a ${p1}".format("world", "test"));
-
Use a tagged template literal. Notice that the substitutions will still be evaluated without interception by the handler, so you cannot use identifiers like
p0
without having a variable named so.This behavior may change if a different substitution body syntax proposal is accepted (Update: it was not).function formatter(literals, ...substitutions) { return { format: function() { var out = []; for(var i=0, k=0; i < literals.length; i++) { out[k++] = literals[i]; out[k++] = arguments[substitutions[i]]; } out[k] = literals[i]; return out.join(""); } }; } console.log(formatter`Hello, ${0}. This is a ${1}`.format("world", "test")); // Notice the number literals: ^ ^