tl;dr: Is it possible to make a reusable template literal?
I've been trying to use template literals but I guess I just don't get it and now I'm getting frustrated. I mean, I think I get it, but "it" shouldn't be how it works, or how it should get. It should get differently.
All the examples I see (even tagged templates) require that the "substitutions" be done at declaration time and not run time, which seems utterly useless to me for a template. Maybe I'm crazy, but a "template" to me is a document that contains tokens which get substituted when you use it, not when you create it, otherwise it's just a document (i.e., a string). A template is stored with the tokens as tokens & those tokens are evaluated when you...evaluate it.
Everyone cites a horrible example similar to:
var a = 'asd';
return `Worthless ${a}!`
That's nice, but if I already know a
, I would just return 'Worthless asd'
or return 'Worthless '+a
. What's the point? Seriously. Okay the point is laziness; fewer pluses, more readability. Great. But that's not a template! Not IMHO. And MHO is all that matters! The problem, IMHO, is that the template is evaluated when it's declared, so, if you do, IMHO:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!
Since expletive
isn't declared, it outputs something like My undefined template
. Super. Actually, in Chrome at least, I can't even declare the template; it throws an error because expletive
is not defined. What I need is to be able to do the substitution after declaring the template:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template
However I don't see how this is possible, since these aren't really templates. Even when you say I should use tags, nope, they don't work:
> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...
This all has led me to believe that template literals are horribly misnamed and should be called what they really are: heredocs. I guess the "literal" part should have tipped me off (as in, immutable)?
Am I missing something? Is there a [good] way to make a reusable template literal?
I give you, reusable template literals:
> function out(t) { console.log(eval(t)); }
var template = `\`This is
my \${expletive} reusable
template!\``;
out(template);
var expletive = 'curious';
out(template);
var expletive = 'AMAZING';
out(template);
< This is
my undefined reusable
template!
This is
my curious reusable
template!
This is
my AMAZING reusable
template!
And here is a naive "helper" function...
function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);
...to make it "better".
I'm inclined to call them template guterals because of the area from which they produce twisty feelings.
This is my best attempt:
To generalify:
If you are not running E6, you could also do:
This seems to be a bit more concise than the previous answers.
https://repl.it/@abalter/reusable-JS-template-literal
Probably the cleanest way to do this is with arrow functions (because at this point, we're using ES6 already)
...And for tagged template literals:
This also avoids the use of
eval()
orFunction()
which can cause problems with compilers and cause a lot of slowdown.In general I'm against using the evil
eval()
, but in this case it makes sense:Then if you change the values and call eval() again you get the new result:
If you want it in a function, then it can be written like so:
2018 answer:
The
es6-dynamic-template
module on npm does this.Unlike the current answers:
this
in the template stringUsage is simple. Use single quotes as the template string will be resolved later!
A simple utility function. No need for external library.
You can put a template string in a function:
You can do the same thing with a tagged template:
The idea is to let the template parser split out the constant strings from the variable "slots", and then return a function that patches it all back together based on a new set of values each time.