How JavaScript Tagged Template Literals Work

Tagged template literals are an advanced feature in JavaScript that allow functions to parse, process, and manipulate template strings. When a tag function is applied to a template literal containing variable substitutions, the JavaScript runtime splits the literal into an array of static string chunks and evaluates the dynamic expressions independently. The tag function then receives these components as distinct arguments, allowing custom logic to determine the final output.

The Mechanics of Evaluation

When JavaScript encounters a tagged template literal (e.g., tagFunction\Hello ${name}!``), it executes the evaluation in a specific sequence:

  1. Expression Evaluation: The engine evaluates all expressions inside the ${...} placeholders from left to right.
  2. Static String Tokenization: The text surrounding the expressions is partitioned into an array of string literals (a TemplateStringsArray).
  3. Function Invocation: The tag function is called. The static strings array is passed as the first argument, followed by each evaluated substitution as separate subsequent arguments.

Argument Structure

A tag function receives arguments matching this signature:

function tag(strings, ...values) {
  // strings is an array of the static string parts
  // values contains the evaluated results of each ${} expression
}

If a template literal has \(N\) expressions, the strings array will always contain \(N + 1\) elements. Even if an expression appears at the very beginning or end of the literal, empty strings are placed into the strings array to maintain this consistency.

Step-by-Step Execution Example

Consider the following code:

function highlight(strings, ...values) {
  return strings.reduce((accumulator, str, index) => {
    const value = values[index] ? `<mark>${values[index]}</mark>` : '';
    return `${accumulator}${str}${value}`;
  }, '');
}

const item = 'laptop';
const price = 999;
const message = highlight`The ${item} costs $${price}.`;

Here is how the engine processes the evaluation:

  1. Evaluate Substitutions: The variables item and price resolve to 'laptop' and 999.
  2. Extract Static Strings: The engine splits the static parts into ['The ', ' costs $', '.'].
  3. Execute Tag Function: The highlight function is called with:
    • strings: ['The ', ' costs $', '.']
    • values: ['laptop', 999]
  4. Return Value: The function iterates over the strings and wraps dynamic values in <mark> tags, returning: "The <mark>laptop</mark> costs $<mark>999</mark>.".

The strings.raw Property

The first argument (strings) contains a special .raw property. This property is an array containing the exact strings as they were written, without interpreting escape sequences (such as \n or \u00A9). This allows tag functions to process raw text for domain-specific languages, regular expressions, or shell commands.

String Immutability and Caching

The strings array passed to a tag function is frozen using Object.freeze(), preventing mutation. In modern JavaScript engines, identical tagged template literals in the same source location share the same cached strings array instance across multiple executions to optimize performance.