tagged template
Tagged templates are template literals with a tag.
They are parsed by its tag function.
The first argument of a tag function contains an array of strings.
The remaining arguments are related to the (interpolation) expressions.
let person = 'Mike';
let age = 28;
// -------------------------
// โญ๏ธ tagged template
// -------------------------
// โญtagโฎ <-- tag function
// โ โ โญโ0โโฎ โญโ1โโโฎ 2 <-- array of strings (p0)
let output = myTag`That ${person} is a ${age}.`;
// โฐโโp1โโโโฏ โฐโp2โโฏ <-- interpolations (p1, p2 ...)
console.log(output);
// That Mike is a youngster.
// -----------------------
// โญ๏ธ tag function
// -----------------------
// โญโarrโโฎ โญโinterpolationsโโฎ
function myTag(strings, personExp, ageExp ) {
// manipulate array of strings
let str0 = strings[0]; // "That "
let str1 = strings[1]; // " is a "
let str2 = strings[2]; // "."
// manipulate interpolations
let ageStr = ageExp > 99 ? 'centenarian' : 'youngster';
return `${str0}${personExp}${str1}${ageStr}${str2}`;
}
// ๐ Array.prototype + .last
Object.assign(Array.prototype, {
get last() { return this[this.length - 1] }
});
// -----------------------
// โญ๏ธ tag function
// -----------------------
// `strings` and interpolated `values` are provided by the template literal
function template(strings, ...values) {
// `args` are provided by the function parameters
return (function (...args) {
// last argument is expected to be an "options" objerct
let opts = args.last || {}; // ๐ Array.prototype + .last
// reconstruct the "template" string (1/3)
let result = [strings[0]];
// for each interpolated value
values.forEach((value, i) => {
// if the value is number, choose from arguments,
// otherwise, choose from the "options" object
let selected = Number.isInteger(value) ? args[value] : opts[value];
// reconstruct the "template" string (2/3)
result.push(selected, strings[i + 1]);
});
// reconstruct the "template" string (3/3)
return result.join('');
});
}
// -------------------------
// โญ๏ธ tagged templates
// -------------------------
template`${0}${1}${0}!`('Y', 'A'), // "YAY!"
// strings: ['', '', '', '!']
// values: [0, 1, 0] <----------- โญ๏ธ choose from `args`
// args: ['Y', 'A']
// opts: 'A' (ignored)
template`${0} ${'foo'}!`('Hello', { foo: 'World' }), // "Hello World!"
// strings: ['', ' ', '!']
// values: [0, 'foo'] <-------------- โญ๏ธ choose from `args` & `opts`
// args: ['Hello', { foo: 'World' }]
// opts: { foo: 'World' }
// โญs0โฎ โญโโโ s1 โโโโโฎ โญโโ s2 โโโโฎ <-- strings
template`I'm ${'name'}. I'm almost ${'age'} years old.`({ name: 'MDN', age: 30 }),
// โฐโ v0 โโโฏ โฐโ v1 โโฏ <------- interpolated values
// result: "I'm MDN. I'm almost 30 years old."
// ---------------------------------------------
// strings: ["I'm ", ". I'm almost ", " years old."]
// values: ['name', 'age'] <----------- โญ๏ธ choose from `opts`
// args: [{ name: 'MDN', age: 30 }] (ignored)
// opts: { name: 'MDN', age: 30 }
destructuring assignment is often used to manipulate interpolation parameters.
Last updated