Templating inline strings is simple using ES6 template literals:
const a = "hello"
const b = "world"
console.log(`${a} ${b}`)
//hello world
But what if you have a string that can't be inlined (i.e. it comes from an external source)?
Here's the gist of the function I recently used for this purpose:
function tpl(str, props) {
let names = Object.keys(props);
let vals = Object.values(props);
return new Function(...names, `return \`${str}\`;`)(...vals);
}
Or, (a slightly less readable) one-liner version:
const tpl = (str, props) => new Function(...Object.keys(props), `return \`${str}\`;`)(...Object.values(props))
Example:
console.log(tpl('${a} ${b}', {a: 'hello', b: 'world'}))
//hello world
Explanation
So, we are defining a function called tpl
:
function tpl(str, props) {
let names = Object.keys(props);
let vals = Object.values(props);
return new Function(...names, `return \`${str}\`;`)(...vals);
}
The first two lines are self-explanatory - we are just extracting keys and values from the passed-in props
object.
In the last line, we are dynamically creating a function from a string. Instead of doing eval
, we are using the Function
constructor, which is a much safer alternative.
Our new (dynamically generated) function receives a list of names of our props keys, and returns the same passed-in str
string but delimited with backtick characters (basically, we are turning our "external" string into an inline template string).
After that, we just need to call our new function with a list of values.
Function.call alternative
We could simplify things by doing something like this instead of extracting names and values:
new Function(`return \`${str}\`;`).call(props)
But then we would need to use ${this.a}
instead of just ${a}
.
Caching
Each time you're calling the Function
constructor, the function body needs to be parsed (some overhead), but it would be very easy to do some caching based on the value of str
.
Note: This is a snapshot of the wiki page from the BetterWays.dev wiki, you can find the latest (better formatted) version here: betterways.dev/simple-javascript-template-engine-by-ab-using-template-literals.
Top comments (0)