Uso letterale con le stringhe dei modelli ES6

Addy Osmani
Addy Osmani

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

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

Anziché inserire un'altra funzionalità nelle stringhe come le conosciamo oggi, le stringhe modello introducono un modo completamente diverso per risolvere questi problemi.

Sintassi

Le stringhe modello utilizzano i backtick (``) anziché le virgolette singole o doppie a cui siamo abituati con le stringhe normali. Una stringa modello potrebbe quindi essere scritta come segue:

var greeting = `Yo World!`;

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

Sostituzione di stringhe

Uno dei primi vantaggi reali è la sostituzione di stringhe. La sostituzione ci consente di prendere qualsiasi espressione JavaScript valida (ad esempio l'aggiunta di variabili) e all'interno di un literal di modello il risultato verrà visualizzato all'interno 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 di più dei nomi delle variabili. Ad esempio, di seguito possiamo utilizzare l'interpolazione di espressioni per incorporare alcuni calcoli in linea leggibili:

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 barre graffe all'interno della stringa, puoi utilizzare il carattere di escape barra rovesciata \ come segue:

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

Stringhe multilinea

Le stringhe multilinea in JavaScript richiedono da tempo soluzioni alternative poco eleganti. Le soluzioni attuali richiedono che le stringhe esistano su una singola riga o siano suddivise in stringhe multiriga utilizzando un carattere \ (barra rovesciata) prima di ogni riga nuova. Ad esempio:

var greeting = "Yo \
World";

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

var greeting = "Yo " +
"World";

Le stringhe modello semplificano notevolmente le stringhe multiriga. Basta includere i ritorni a capo dove sono necessari e BOOM. Ecco un esempio:

Anche gli spazi all'interno della sintassi dei simboli "backtick" verranno considerati parte della stringa.

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

Modelli con tag

Finora abbiamo esaminato l'utilizzo delle stringhe modello per la sostituzione di stringhe e per la creazione di stringhe multilinee. Un'altra potente funzionalità che offrono sono i modelli con tag. I modelli con tag trasformano una stringa modello inserendo un nome di 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 normale. In sostanza, sono un tipo speciale di chiamata di funzione: il codice precedente viene "desugarizzato" in

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

Nota come l'argomento (n + 1) corrisponde alla sostituzione che avviene tra la riga n e la riga (n + 1) nell'array di stringhe. Questo può essere utile per vari scopi, ma uno dei più semplici è l'escapismo automatico di eventuali variabili interpolate.

Ad esempio, puoi 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 HTML sostituiti. Facciamo così. La nostra funzione di estrazione di HTML accetta due argomenti: un nome utente e un commento. Entrambi possono contenere caratteri non sicuri HTML (ovvero ", ", <, > e &). Ad esempio, se il nome utente è "Domenic Denicola" e il commento è "& è un tag divertente", l'output dovrebbe essere:

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

La nostra soluzione di modelli con tag 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'escapismo 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 e versioni successive, IE Tech Preview, Firefox 35 e versioni successive e io.js. In pratica, se vuoi utilizzarli in produzione oggi, 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 l'articolo Equivalenti di ES6 in ES5, che mostra come ottenere alcune delle funzionalità di sugaring delle stringhe di modello utilizzando ES5.

Le stringhe di modello offrono molte funzionalità importanti a JavaScript. Sono inclusi metodi migliori per eseguire l'interpolazione di stringhe ed espressioni, stringhe multilinea e la possibilità di creare i tuoi DSL.

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

Per approfondire