Uso letterale con le stringhe dei modelli ES6

Le stringhe in JavaScript sono sempre state limitate e non offrono le funzionalità che ci si aspetterebbe da linguaggi come Python o Ruby. Le stringhe modello ES6 (disponibili in Chrome 41 e versioni successive) cambiano radicalmente la situazione. Introducono un modo per definire le stringhe con linguaggi specifici del dominio (DSL), offrendo:

  • Interpolazione di stringhe
  • Espressioni incorporate
  • Stringhe multiriga senza trucchi
  • Formattazione delle stringhe
  • Tagging delle stringhe per l'escape sicuro dell'HTML, la localizzazione e altro ancora.

Anziché aggiungere un'altra funzionalità alle stringhe come le conosciamo oggi, le stringhe modello introducono un modo completamente diverso di risolvere questi problemi.

Sintassi

Le stringhe modello utilizzano gli apici inversi (``) anziché gli apici singoli o doppi a cui siamo abituati con le stringhe normali. Una stringa modello potrebbe quindi essere scritta nel seguente modo:

var greeting = `Yo World!`;

Finora, le stringhe modello non ci hanno dato nulla di più di quanto facciano le stringhe normali. Cambiamo la situazione.

Sostituzione di stringhe

Uno dei primi vantaggi reali è la sostituzione delle stringhe. La sostituzione ci consente di prendere qualsiasi espressione JavaScript valida (inclusa, ad esempio, l'addizione di variabili) e, all'interno di un letterale modello, il risultato verrà restituito come parte della stessa stringa.

Le stringhe modello possono contenere segnaposto per la sostituzione di stringhe utilizzando la sintassi ${ }, come mostrato di seguito:

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

// => "Yo, Brendan!"

Poiché tutte le sostituzioni di stringhe nelle stringhe modello sono espressioni JavaScript, possiamo sostituire molto più dei nomi delle variabili. Ad esempio, di seguito possiamo utilizzare l'interpolazione delle espressioni per incorporare un po' di matematica in linea leggibile:

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.

Sono molto utili anche per le funzioni all'interno delle espressioni:

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

${} funziona correttamente con qualsiasi tipo di espressione, incluse le espressioni dei membri e le chiamate ai metodi:

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

Se hai bisogno di apici inversi all'interno della stringa, puoi utilizzare il carattere di escape con la barra rovesciata \ nel seguente modo:

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

Stringhe multilinea

Le stringhe multiline in JavaScript richiedono da tempo soluzioni alternative. Le soluzioni attuali richiedono che le stringhe si trovino su una sola riga o siano suddivise in stringhe multiriga utilizzando un \ (backslash) prima di ogni nuova riga. Ad esempio:

var greeting = "Yo \
World";

Sebbene questo dovrebbe funzionare correttamente nella maggior parte dei motori JavaScript moderni, il comportamento in sé è ancora un po' un hack. È anche possibile utilizzare la concatenazione di stringhe per simulare il supporto multiriga, ma anche questo lascia a desiderare:

var greeting = "Yo " +
"World";

Le stringhe modello semplificano notevolmente le stringhe multiriga. Ti basta includere i nuovi caratteri di fine riga dove sono necessari e il gioco è fatto. Ecco un esempio:

Anche gli spazi vuoti all'interno della sintassi del backtick verranno considerati parte della stringa.

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

Modelli taggati

Finora abbiamo visto come utilizzare le stringhe modello per la sostituzione di stringhe e per la creazione di stringhe multilinee. Un'altra funzionalità potente che offrono sono i modelli con tag. I modelli con tag trasformano una stringa modello inserendo il nome di una funzione prima della stringa modello. Ad esempio:

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

La semantica di una stringa di modello con tag è molto diversa da quella di una stringa normale. In sostanza, sono un tipo speciale di chiamata di funzione: la precedente "desugars" in

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

Nota come l'argomento (n + 1) corrisponda alla sostituzione che avviene tra la n-esima e la (n + 1)-esima voce nell'array di stringhe. Può essere utile per una serie di cose, ma una delle più semplici è l'escape automatico di qualsiasi variabile interpolata.

Ad esempio, potresti scrivere una funzione di escape HTML in modo che…

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

restituisce una stringa con le variabili appropriate sostituite, ma con tutti i caratteri non sicuri per l'HTML sostituiti. Facciamolo. La nostra funzione di escape HTML accetterà due argomenti: un nome utente e un commento. Entrambi possono contenere caratteri non sicuri per HTML (ovvero ', ", <, > e &). Ad esempio, se il nome utente è "Domenic Denicola" e il commento è "& is a fun tag", l'output dovrebbe essere:

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

La nostra soluzione di modelli taggati potrebbe quindi essere scritta come segue:

// 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"

Altri possibili utilizzi includono l'escape automatico, la formattazione, la localizzazione e, in generale, sostituzioni più complesse:

// 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}`;

Riepilogo

Le stringhe modello sono disponibili in Chrome 41 beta+, IE Tech Preview, Firefox 35+ e io.js. In termini pratici, se vuoi utilizzarli oggi in produzione, sono supportati nei principali transpiler ES6, tra cui Traceur e 6to5. Se vuoi provarli, dai un'occhiata al nostro esempio di stringhe modello nel repository di esempi di Chrome. Potrebbe interessarti anche ES6 Equivalents in ES5, che mostra come ottenere alcune delle funzionalità delle stringhe modello utilizzando ES5 oggi.

Le stringhe modello offrono molte funzionalità importanti a JavaScript. Questi includono modi migliori per eseguire l'interpolazione di stringhe ed espressioni, stringhe multiriga e la possibilità di creare DSL personalizzate.

Una delle funzionalità più importanti che offrono sono i modelli taggati, una funzionalità fondamentale per la creazione di queste DSL. Ricevono le parti di una stringa modello come argomenti e puoi quindi decidere come utilizzare le stringhe e le sostituzioni per determinare l'output finale della stringa.

Per approfondire