Literal mit ES6-Vorlagenstrings abrufen

Addy Osmani
Addy Osmani

Strings in JavaScript waren bisher eingeschränkt und boten nicht die Funktionen, die man von Sprachen wie Python oder Ruby erwarten würde. Mit ES6-Template Strings (verfügbar in Chrome 41 und höher) ändert sich das grundlegend. Sie ermöglichen die Definition von Strings mit domainspezifischen Sprachen (DSLs) und bieten folgende Vorteile:

  • String-Interpolation
  • Eingebettete Ausdrücke
  • Mehrzeilige Strings ohne Hacks
  • Stringformatierung
  • String-Tagging für sicheres HTML-Escaping, Lokalisierung und mehr.

Anstatt Strings noch eine weitere Funktion hinzuzufügen, wie wir sie heute kennen, bieten Vorlagenstrings eine völlig andere Möglichkeit, diese Probleme zu lösen.

Syntax

Für Vorlagenstrings werden Backticks (``) anstelle der einfachen oder doppelten Anführungszeichen verwendet, die bei regulären Strings üblich sind. Ein Vorlagen-String könnte also so geschrieben werden:

var greeting = `Yo World!`;

Bisher haben wir mit Vorlagenstrings nicht mehr erreicht als mit normalen Strings. Das wollen wir ändern.

String-Ersetzung

Einer der ersten echten Vorteile ist die String-Ersetzung. Mithilfe der Substitution können wir jeden gültigen JavaScript-Ausdruck (z. B. die Addition von Variablen) in ein Vorlagenliteral einfügen. Das Ergebnis wird dann als Teil desselben Strings ausgegeben.

Vorlagenstrings können Platzhalter für die Stringsubstitution mit der ${ }-Syntax enthalten, wie unten gezeigt:

// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);

// => "Yo, Brendan!"

Da alle Stringersetzungen in Vorlagenstrings JavaScript-Ausdrücke sind, können wir viel mehr als nur Variablennamen ersetzen. Im folgenden Beispiel können wir beispielsweise die Ausdrucksinterpolation verwenden, um lesbare Inline-Mathematik einzubetten:

var a = 10;
var b = 10;
console.log(`JavaScript first appeared ${a+b} years ago. Wow!`);

//=> JavaScript first appeared 20 years ago. Wow!

console.log(`The number of JS MVC frameworks is ${2 * (a + b)} and not ${10 * (a + b)}.`);
//=> The number of JS frameworks is 40 and not 200.

Sie sind auch sehr nützlich für Funktionen in Ausdrücken:

function fn() { return "I am a result. Rarr"; }
console.log(`foo ${fn()} bar`);
//=> foo I am a result. Rarr bar.

${} funktioniert mit jeder Art von Ausdruck, einschließlich Mitgliedsausdrücken und Methodenaufrufen:

var user = {name: 'Caitlin Potter'};
console.log(`Thanks for getting this into V8, ${user.name.toUpperCase()}.`);

// => "Thanks for getting this into V8, CAITLIN POTTER";

// And another example
var thing = 'template strings';
console.log(`Say hello to ${thing}.`);

// => Say hello to template strings

Wenn Sie Backticks innerhalb Ihres Strings benötigen, können Sie sie mit dem umgekehrten Schrägstrich \ so maskieren:

var greeting = `\`Yo\` World!`;

Mehrzeilige Strings

Für mehrzeilige Strings in JavaScript waren schon seit einiger Zeit umständliche Umwege erforderlich. Für aktuelle Lösungen müssen Strings entweder in einer einzigen Zeile vorhanden sein oder durch ein \ (Backslash) vor jedem Zeilenumbruch in mehrzeilige Strings aufgeteilt werden. Beispiel:

var greeting = "Yo \
World";

Das sollte in den meisten modernen JavaScript-Engines gut funktionieren, das Verhalten selbst ist jedoch immer noch ein bisschen ein Hack. Mithilfe der Stringkonkatenierung lässt sich auch eine Unterstützung für mehrzeilige Strings vortäuschen, was aber ebenfalls zu wünschen übrig lässt:

var greeting = "Yo " +
"World";

Vorlagenstrings vereinfachen mehrzeilige Strings erheblich. Fügen Sie einfach dort, wo es nötig ist, neue Zeilen ein. Beispiel:

Alle Leerzeichen innerhalb der Backticks werden ebenfalls als Teil des Strings betrachtet.

console.log(`string text line 1
string text line 2`);

Getaggte Vorlagen

Bisher haben wir uns damit beschäftigt, wie Sie Vorlagenstrings für die Stringsubstitution und zum Erstellen mehrzeiliger Strings verwenden. Eine weitere nützliche Funktion sind getaggte Vorlagen. Bei getaggten Vorlagen wird ein Vorlagenstring durch Platzieren eines Funktionsnamens vor dem Vorlagenstring transformiert. Beispiel:

fn`Hello ${you}! You're looking ${adjective} today!`

Die Semantik eines getaggten Vorlagenstrings unterscheidet sich stark von der eines normalen Strings. Im Grunde sind sie eine spezielle Art von Funktionsaufruf: Der obige Code wird in

fn(["Hello ", "! You're looking ", " today!"], you, adjective);

Das (n + 1)te Argument entspricht der Substitution, die zwischen dem n-ten und dem (n + 1)ten Eintrag im Stringarray erfolgt. Das kann für viele Zwecke nützlich sein, aber eine der einfachsten Anwendungen ist das automatische Entkommentieren aller interpolierten Variablen.

So könnten Sie beispielsweise eine HTML-Entkommensfunktion schreiben:

html`<p title="${title}">Hello ${you}!</p>`

gibt einen String zurück, in dem die entsprechenden Variablen ersetzt wurden, aber alle für HTML ungültigen Zeichen. Lassen Sie uns das tun. Unsere HTML-Entkommentierungsfunktion nimmt zwei Argumente an: einen Nutzernamen und einen Kommentar. Beide können HTML-unsichere Zeichen enthalten, nämlich ', ", <, > und &. Wenn der Nutzername beispielsweise „Domenic Denicola“ und der Kommentar „& ist ein lustiges Tag“ lautet, sollte Folgendes ausgegeben werden:

<b>Domenic Denicola says:</b> "&amp; is a fun tag"

Unsere getaggte Vorlagenlösung könnte also so geschrieben werden:

// HTML Escape helper utility
var util = (function () {
    // Thanks to Andrea Giammarchi
    var
    reEscape = /[&<>'"]/g,
    reUnescape = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g,
    oEscape = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        "'": '&#39;',
        '"': '&quot;'
    },
    oUnescape = {
        '&amp;': '&',
        '&#38;': '&',
        '&lt;': '<',
        '&#60;': '<',
        '&gt;': '>',
        '&#62;': '>',
        '&apos;': "'",
        '&#39;': "'",
        '&quot;': '"',
        '&#34;': '"'
    },
    fnEscape = function (m) {
        return oEscape[m];
    },
    fnUnescape = function (m) {
        return oUnescape[m];
    },
    replace = String.prototype.replace
    ;
    return (Object.freeze || Object)({
    escape: function escape(s) {
        return replace.call(s, reEscape, fnEscape);
    },
    unescape: function unescape(s) {
        return replace.call(s, reUnescape, fnUnescape);
    }
    });
}());

// Tagged template function
function html(pieces) {
    var result = pieces[0];
    var substitutions = [].slice.call(arguments, 1);
    for (var i = 0; i < substitutions.length; ++i) {
        result += util.escape(substitutions[i]) + pieces[i + 1];
    }

    return result;
}

var username = "Domenic Denicola";
var tag = "& is a fun tag";
console.log(html`<b>${username} says</b>: "${tag}"`);
//=> <b>Domenic Denicola says</b>: "&amp; is a fun tag"

Weitere mögliche Verwendungen sind automatisches Entkommenttieren, Formatierung, Lokalisierung und im Allgemeinen komplexere Ersetzungen:

// Contextual auto-escaping
qsa`.${className}`;
safehtml`<a href="${url}?q=${query}" onclick="alert('${message}')" style="color: ${color}">${message}</a>`;

// Localization and formatting
l10n`Hello ${name}; you are visitor number ${visitor}:n! You have ${money}:c in your account!`

// Embedded HTML/XML
jsx`<a href="${url}">${text}</a>` // becomes React.DOM.a({ href: url }, text)

// DSLs for code execution
var childProcess = sh`ps ax | grep ${pid}`;

Zusammenfassung

Vorlagenstrings werden in Chrome 41 Beta und höher, im IE Tech Preview, in Firefox 35 und höher sowie in io.js unterstützt. Wenn Sie sie in der Produktion verwenden möchten, werden sie von den wichtigsten ES6-Transpilern unterstützt, darunter Traceur und 6to5. Im Chrome-Beispiel-Repository finden Sie das Beispiel für Vorlagenstrings, das Sie ausprobieren können. Möglicherweise interessieren Sie sich auch für ES6-Äquivalente in ES5, in dem gezeigt wird, wie Sie einige der Vorteile von Vorlagenstrings mit ES5 erzielen können.

Vorlagenstrings bieten JavaScript viele wichtige Funktionen. Dazu gehören bessere Möglichkeiten zur String- und Ausdrucksinterpolation, mehrzeilige Strings und die Möglichkeit, eigene DSLs zu erstellen.

Eines der wichtigsten Merkmale sind getaggte Vorlagen, eine wichtige Funktion für die Erstellung solcher DSLs. Sie erhalten die Teile eines Vorlagenstrings als Argumente und Sie können dann entscheiden, wie Sie die Strings und Ersetzungen verwenden, um die endgültige Ausgabe des Strings zu bestimmen.

Weiterführende Literatur