Ciągi znaków w JavaScript były do tej pory ograniczone, ponieważ brakowało im możliwości, których można oczekiwać w językach takich jak Python czy Ruby. Stringi szablonów w ES6 (dostępne w Chrome 41 i nowszych wersjach) całkowicie zmieniają tę sytuację. Wprowadzają sposób definiowania ciągów za pomocą języków specyficznych dla domeny (DSL), co zapewnia lepsze:
- Interpolacja ciągu
- Umieszczone wyrażenia
- Ciągi wielowierszowe bez obejść.
- Formatowanie ciągu
- Tagowanie ciągów znaków na potrzeby bezpiecznego ucieczki znaków HTML, lokalizacji i innych działań.
Zamiast dodawać kolejną funkcję do ciągów tekstowych, jakie znamy obecnie, ciągi tekstowe w szablonach wprowadzają zupełnie nowy sposób rozwiązywania tych problemów.
Składnia
Ciągi szablonów używają cudzysłowów tylnych (``), a nie pojedynczych ani podwójnych cudzysłowów, które są używane w zwykłych ciągach. Ciąg znaków szablonu może więc mieć postać:
var greeting = `Yo World!`;
Do tej pory ciągi tekstowe szablonów nie dawały nam niczego więcej niż zwykłe ciągi tekstowe. Zmieńmy to.
Zastępowanie ciągów tekstowych
Jednym z pierwszych realnych korzyści jest zastępowanie ciągów znaków. Zastąpienie pozwala nam wziąć dowolne prawidłowe wyrażenie JavaScript (w tym np. dodanie zmiennych) i w ramach literalu szablonu, a wynik zostanie wyświetlony jako część tego samego ciągu znaków.
ciągi znaków szablonu mogą zawierać wartości zastępcze w postaci składni ${ }
, jak pokazano poniżej:
// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);
// => "Yo, Brendan!"
Wszystkie zamiany ciągów znaków w ciągu szablonu są wyrażeniami JavaScriptu, więc możemy zastępować znacznie więcej niż tylko nazwy zmiennych. Poniżej możesz zobaczyć, jak za pomocą interpolacji wyrażeń można wstawić czytelny tekst matematyczny:
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.
Są też bardzo przydatne w przypadku funkcji wewnątrz wyrażeń:
function fn() { return "I am a result. Rarr"; }
console.log(`foo ${fn()} bar`);
//=> foo I am a result. Rarr bar.
Funkcja ${}
działa z dowolnym wyrażeniem, w tym z wyrażeniami członków i wywołaniami metod:
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
Jeśli w łańcuchu tekstowym chcesz użyć cudzysłowów, możesz je zamienić na znaki ukośniki ukośne \
w ten sposób:
var greeting = `\`Yo\` World!`;
Teksty wielowierszowe
Wielokrotne ciągi znaków w JavaScript wymagały do tej pory stosowania niestandardowych obejść. Obecne rozwiązania wymagają, aby ciągi znaków znajdowały się na jednym wierszu lub były podzielone na ciągi znaków wielowierszowych za pomocą znaku \
(ukośnika wstecznego) przed każdym nowym wierszem. Na przykład:
var greeting = "Yo \
World";
Ta metoda powinna działać w większości nowoczesnych silników JavaScript, ale samo zachowanie jest nadal nieco niestandardowe. Można też użyć złączenia ciągu znaków, aby symulować obsługę wielu wierszy, ale i to rozwiązanie ma swoje wady:
var greeting = "Yo " +
"World";
Ciągi znaków szablonu znacznie upraszczają ciągi znaków wielowierszowych. Po prostu dodaj znaki nowej linii tam, gdzie są potrzebne, i gotowe. Oto przykład:
Wszystkie spacje w nawiasach cudzysłownych również będą uważane za część ciągu.
console.log(`string text line 1
string text line 2`);
Otagowane szablony
Do tej pory omawialiśmy używanie ciągów znaków szablonowych do zastępowania ciągów znaków i tworzenia ciągów znaków wielowierszowych. Kolejną przydatną funkcją są szablony z tagami. Tagowane szablony przekształcają ciąg znaków szablonu, umieszczając przed nim nazwę funkcji. Na przykład:
fn`Hello ${you}! You're looking ${adjective} today!`
Semantyka otagowanego ciągu szablonu różni się znacznie od semantyki zwykłego ciągu. Zasadniczo są one specjalnym typem wywołania funkcji: powyższy kod „desugars” w postaci
fn(["Hello ", "! You're looking ", " today!"], you, adjective);
Zwróć uwagę, że (n + 1)-ty argument odpowiada zastępowaniu, które ma miejsce między n-tym a (n + 1)-tym wpisem w tablicy ciągów znaków. Może to być przydatne na wiele sposobów, ale jednym z najprostszych zastosowań jest automatyczne uciekanie z dowolnych interpolowanych zmiennych.
Możesz na przykład napisać funkcję do kodowania znaków w HTML, która:
html`<p title="${title}">Hello ${you}!</p>`
zwraca ciąg znaków z odpowiednimi zmiennymi, ale ze wszystkimi znakami niebezpiecznymi w HTML. Zrobimy to. Nasza funkcja kodowania znaków HTML będzie przyjmować 2 argumenty: nazwę użytkownika i komentarz. Oba mogą zawierać niebezpieczne znaki HTML (czyli ', ", <, > i &). Jeśli na przykład nazwa użytkownika to „Domenic Denicola”, a komentarz to „& to zabawny tag”, wyjściowo powinno być:
<b>Domenic Denicola says:</b> "& is a fun tag"
Nasz tagowany szablon może więc wyglądać tak:
// 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 = {
'&': '&',
'<': '<',
'>': '>',
"'": ''',
'"': '"'
},
oUnescape = {
'&': '&',
'&': '&',
'<': '<',
'<': '<',
'>': '>',
'>': '>',
''': "'",
''': "'",
'"': '"',
'"': '"'
},
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>: "& is a fun tag"
Inne możliwe zastosowania to automatyczne ucieczki, formatowanie, lokalizacja i ogółem bardziej złożone zamiany:
// 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}`;
Podsumowanie
Ciągi znaków szablonu są dostępne w Chrome 41 beta i nowszych wersjach, IE Tech Preview, Firefox 35 i nowszych wersjach oraz io.js. Jeśli chcesz używać ich w produkcji, pamiętaj, że są one obsługiwane w głównych transpilerach ES6, takich jak Traceur i 6to5. Jeśli chcesz je wypróbować, zajrzyj do pliku ze stringami szablonów w repozytorium z przykładami kodu Chrome. Możesz też zainteresować się artykułem ES6 Equivalents in ES5 (Tłumaczenie: „Odpowiedniki ES6 w ES5”), który pokazuje, jak uzyskać niektóre z funkcji dostępnych dzięki użyciu napisów w kodzie w wersji ES5.
Ciągi znaków szablonu zapewniają JavaScriptowi wiele ważnych funkcji. Dotyczą one m.in. ulepszonych sposobów interpolowania ciągu i wyrażenia, wielowierszowych ciągów oraz możliwości tworzenia własnych DSL.
Jedną z najważniejszych funkcji są szablony z tagami – kluczowa funkcja do tworzenia takich DSL. Otrzymuje ona jako argumenty części ciągu znaków w szablonie, a potem możesz określić, jak za pomocą tych ciągów i podstaw zastąpić końcowy ciąg znaków.