בעבר, מחרוזות ב-JavaScript היו מוגבלות ולא כללו את היכולות שאפשר לצפות להן משפות כמו Python או Ruby. ES6 Template Strings (זמין ב-Chrome 41 ואילך) משנה את זה באופן מהותי. הם מציגים דרך להגדיר מחרוזות באמצעות שפות ספציפיות לדומיין (DSL), וכך משפרים את:
- String interpolation
- ביטויים מוטמעים
- מחרוזות מרובות שורות בלי פתרונות עקיפים
- עיצוב מחרוזות
- תיוג מחרוזות להסרת תווים מיוחדים מ-HTML, לוקליזציה ועוד.
במקום להוסיף עוד תכונה למחרוזות כמו שהן היום, מחרוזות תבנית מציעות דרך שונה לגמרי לפתרון הבעיות האלה.
תחביר
במחרוזות תבנית משתמשים בגרשיים הפוכים (``) ולא בגרשיים יחידים או כפולים כמו במחרוזות רגילות. לכן, מחרוזת תבנית יכולה להיכתב כך:
var greeting = `Yo World!`;
עד עכשיו, מחרוזות התבנית לא סיפקו לנו שום דבר מעבר למה שמחרוזות רגילות מספקות. בואו נשנה את זה.
החלפת מחרוזות
אחד היתרונות הראשונים והאמיתיים שלהם הוא החלפת מחרוזות. החלפה מאפשרת לנו לקחת כל ביטוי JavaScript תקין (כולל, למשל, חיבור של משתנים) ובתוך Template Literal, התוצאה תוצג כחלק מאותה מחרוזת.
מחרוזות תבנית יכולות להכיל placeholders להחלפת מחרוזות באמצעות התחביר ${ }, כמו בדוגמה הבאה:
// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);
// => "Yo, Brendan!"
מכיוון שכל ההחלפות של מחרוזות ב-Template Strings הן ביטויי JavaScript, אפשר להחליף הרבה יותר משמות של משתנים. לדוגמה, בהמשך אנחנו יכולים להשתמש באינטרפולציה של ביטויים כדי להטמיע מתמטיקה קריאה בשורה:
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.
הן שימושיות מאוד גם לפונקציות בתוך ביטויים:
function fn() { return "I am a result. Rarr"; }
console.log(`foo ${fn()} bar`);
//=> foo I am a result. Rarr bar.
התכונה ${} פועלת היטב עם כל סוג של ביטוי, כולל ביטויי חברים והפעלות method:
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
אם אתם צריכים להשתמש בגרש הפוך בתוך המחרוזת, אפשר לסמן אותו בתו בריחה (escape) באמצעות התו לוכסן הפוך \ באופן הבא:
var greeting = `\`Yo\` World!`;
מחרוזות מרובות שורות
כבר זמן מה שנדרשים פתרונות עקיפים מסובכים למחרוזות מרובות שורות ב-JavaScript. הפתרונות הקיימים מחייבים שהמחרוזות יהיו בשורה אחת או יפוצלו למחרוזות מרובות שורות באמצעות \ (קו נטוי הפוך) לפני כל שורה חדשה. לדוגמה:
var greeting = "Yo \
World";
למרות שהשיטה הזו אמורה לעבוד בצורה תקינה ברוב מנועי JavaScript המודרניים, ההתנהגות עצמה היא עדיין סוג של פתרון עקיף. אפשר גם להשתמש בשרשור מחרוזות כדי ליצור תמיכה מזויפת בשורות מרובות, אבל גם כאן התוצאה לא מושלמת:
var greeting = "Yo " +
"World";
מחרוזות תבנית מפשטות מאוד מחרוזות מרובות שורות. פשוט מוסיפים מעברי שורה במקומות שצריך, וזהו. לדוגמה:
גם רווחים בתוך התחביר של הגרש האחורי ייחשבו כחלק מהמחרוזת.
console.log(`string text line 1
string text line 2`);
תבניות מתויגות
עד עכשיו ראינו איך משתמשים ב-Template Strings להחלפת מחרוזות וליצירת מחרוזות מרובות שורות. תכונה חשובה נוספת שהם מציעים היא תבניות מתויגות. תבניות מתויגות משנות מחרוזת תבנית על ידי הצבת שם פונקציה לפני מחרוזת התבנית. לדוגמה:
fn`Hello ${you}! You're looking ${adjective} today!`
הסמנטיקה של מחרוזת תבנית מתויגת שונה מאוד מזו של מחרוזת רגילה. בעצם, הן סוג מיוחד של בקשה להפעלת פונקציה: הקוד שלמעלה עובר 'פירוק' ל-
fn(["Hello ", "! You're looking ", " today!"], you, adjective);
שימו לב איך הארגומנט ה-(n + 1) מתאים להחלפה שמתבצעת בין הרשומה ה-n לרשומה ה-(n + 1) במערך המחרוזות. האפשרות הזו יכולה להיות שימושית לכל מיני דברים, אבל אחד השימושים הפשוטים ביותר הוא ביטול אוטומטי של כל המשתנים שמוצבים בין גרשיים.
לדוגמה, אפשר לכתוב פונקציה להסרת תווים מיוחדים מ-HTML כך ש…
html`<p title="${title}">Hello ${you}!</p>`
הפונקציה מחזירה מחרוזת עם המשתנים המתאימים שהוחלפו, אבל כל התווים שאינם בטוחים לשימוש ב-HTML מוחלפים. בוא נתחיל. פונקציית ה-HTML-escaping שלנו תקבל שני ארגומנטים: שם משתמש ותגובה. שניהם עשויים להכיל תווים לא בטוחים לשימוש ב-HTML (כלומר ', ", <, > ו-&). לדוגמה, אם שם המשתמש הוא Domenic Denicola והתגובה היא "& is a fun tag", הפלט צריך להיות:
<b>Domenic Denicola says:</b> "& is a fun tag"
לכן, אפשר לכתוב את פתרון התבנית המתויגת שלנו כך:
// 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"
שימושים אפשריים אחרים כוללים ביטול אוטומטי של תווים מיוחדים, עיצוב, לוקליזציה ובאופן כללי, החלפות מורכבות יותר:
// 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}`;
סיכום
מחרוזות תבנית זמינות ב-Chrome 41 בטא ומעלה, ב-IE Tech Preview, ב-Firefox 35 ומעלה וב-io.js. מבחינה מעשית, אם אתם רוצים להשתמש בהם בסביבת ייצור היום, יש תמיכה בהם ברוב כלי ה-Transpiler של ES6, כולל Traceur ו-6to5. כדי לנסות את המחרוזות האלה, אפשר לעיין בדוגמה למחרוזות של תבניות במאגר הדוגמאות של Chrome. אולי יעניין אותך גם המאמר ES6 Equivalents in ES5 (מקבילות של ES6 ב-ES5), שמדגים איך להשיג חלק מהיתרונות של מחרוזות תבנית באמצעות ES5 היום.
מחרוזות תבנית מוסיפות ל-JavaScript הרבה יכולות חשובות. בין היתר, הוספנו דרכים טובות יותר לבצע אינטרפולציה של מחרוזות וביטויים, מחרוזות מרובות שורות ואפשרות ליצור שפות תיאוריות משלכם.
אחת התכונות המשמעותיות ביותר שהם מביאים היא תבניות מתויגות – תכונה חיונית ליצירת שפות תצורה כאלה. הם מקבלים את החלקים של Template String כארגומנטים, ואז אתם יכולים להחליט איך להשתמש במחרוזות ובהחלפות כדי לקבוע את הפלט הסופי של המחרוזת.