ในอดีต สตริงใน JavaScript มีข้อจำกัดและไม่มีความสามารถที่อาจคาดหวังได้จากภาษาอย่าง Python หรือ Ruby สตริงเทมเพลต ES6 (พร้อมใช้งานใน Chrome 41 ขึ้นไป) เปลี่ยนแปลงสิ่งนี้โดยพื้นฐาน ซึ่งจะช่วยให้คุณกำหนดสตริงด้วยภาษาเฉพาะโดเมน (DSL) ได้ ซึ่งจะช่วยให้คุณได้รับสิ่งต่อไปนี้
- การแทรกสตริง
- นิพจน์ที่ฝัง
- สตริงหลายบรรทัดโดยไม่ต้องใช้แฮ็ก
- การจัดรูปแบบสตริง
- การติดแท็กสตริงเพื่อการหลีก HTML ที่ปลอดภัย การแปล และอื่นๆ
แทนที่จะยัดฟีเจอร์อีกอย่างลงในสตริงอย่างที่เราทราบกันในปัจจุบัน สตริงเทมเพลตจะนำเสนอวิธีที่แตกต่างอย่างสิ้นเชิงในการแก้ปัญหาเหล่านี้
ไวยากรณ์
สตริงเทมเพลตใช้เครื่องหมายแบ็กทิก (``) แทนเครื่องหมายคำพูดเดี่ยวหรือคู่ที่เราคุ้นเคยกับสตริงปกติ ดังนั้น คุณจึงเขียนสตริงเทมเพลตได้ดังนี้
var greeting = `Yo World!`;
จนถึงตอนนี้ สตริงเทมเพลตยังไม่ได้ให้สิ่งใดแก่เรามากกว่าสตริงปกติเลย มาเปลี่ยนกัน
การแทนที่สตริง
ประโยชน์ที่แท้จริงอย่างแรกคือการแทนที่สตริง การแทนที่ช่วยให้เราใช้การแสดงออก JavaScript ที่ถูกต้อง (รวมถึงการบวกตัวแปร) และภายใน Template Literal ผลลัพธ์จะแสดงเป็นส่วนหนึ่งของสตริงเดียวกัน
สตริงเทมเพลตมีตัวยึดตำแหน่งสำหรับการแทนที่สตริงได้โดยใช้ไวยากรณ์ ${ } ดังที่แสดงด้านล่าง
// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);
// => "Yo, Brendan!"
เนื่องจากการแทนที่สตริงทั้งหมดในสตริงเทมเพลตเป็นนิพจน์ 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.
${} ใช้ได้กับนิพจน์ทุกประเภท รวมถึงนิพจน์ของสมาชิกและการเรียกใช้เมธอด
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
หากต้องการใช้เครื่องหมายแบ็กทิกภายในสตริง คุณสามารถกำหนดให้เป็นอักขระหลีกได้โดยใช้เครื่องหมายแบ็กสแลช \ ดังนี้
var greeting = `\`Yo\` World!`;
สตริงหลายบรรทัด
สตริงหลายบรรทัดใน JavaScript ต้องใช้การแก้ปัญหาแบบไม่เป็นทางการมาสักระยะหนึ่งแล้ว โซลูชันปัจจุบันสำหรับสตริงเหล่านี้กำหนดให้สตริงต้องอยู่ในบรรทัดเดียวหรือแยกเป็นสตริงหลายบรรทัดโดยใช้ \ (แบ็กสแลช) ก่อนแต่ละบรรทัดใหม่ เช่น
var greeting = "Yo \
World";
แม้ว่าวิธีนี้จะใช้ได้ดีในเครื่องมือ JavaScript สมัยใหม่ส่วนใหญ่ แต่ลักษณะการทำงานของวิธีนี้ก็ยังคงเป็นการแฮ็กอยู่ นอกจากนี้ยังใช้การเชื่อมโยงสตริงเพื่อจำลองการรองรับหลายบรรทัดได้ด้วย แต่ก็ยังไม่ดีเท่าที่ควรเช่นกัน
var greeting = "Yo " +
"World";
Template Strings ช่วยลดความซับซ้อนของสตริงหลายบรรทัดได้อย่างมาก เพียงใส่บรรทัดใหม่ในตำแหน่งที่ต้องการ แล้วก็เรียบร้อย เช่น
ระบบจะถือว่าการเว้นวรรคใดๆ ภายในไวยากรณ์เครื่องหมายแบ็กทิกเป็นส่วนหนึ่งของสตริงด้วย
console.log(`string text line 1
string text line 2`);
เทมเพลตที่ติดแท็ก
ที่ผ่านมา เราได้ดูการใช้สตริงเทมเพลตสำหรับการแทนที่สตริงและการสร้างสตริงหลายบรรทัด อีกฟีเจอร์ที่มีประสิทธิภาพคือเทมเพลตที่ติดแท็ก เทมเพลตที่ติดแท็กจะแปลงสตริงเทมเพลตโดยวางชื่อฟังก์ชันไว้หน้าสตริงเทมเพลต เช่น
fn`Hello ${you}! You're looking ${adjective} today!`
ความหมายของสตริงเทมเพลตที่ติดแท็กจะแตกต่างจากสตริงปกติมาก โดยพื้นฐานแล้ว การเรียกใช้ฟังก์ชันเหล่านี้เป็นการเรียกใช้ฟังก์ชันประเภทพิเศษ ซึ่ง "desugars" ข้างต้นจะกลายเป็น
fn(["Hello ", "! You're looking ", " today!"], you, adjective);
โปรดสังเกตว่าอาร์กิวเมนต์ที่ (n + 1) จะสอดคล้องกับการแทนที่ที่เกิดขึ้นระหว่างรายการที่ n และ (n + 1) ในอาร์เรย์สตริง ซึ่งมีประโยชน์ในหลายๆ ด้าน แต่หนึ่งในประโยชน์ที่ตรงไปตรงมาที่สุดคือการหลีกเลี่ยงตัวแปรที่แทรกโดยอัตโนมัติ
เช่น คุณอาจเขียนฟังก์ชันการหลีกเลี่ยง HTML เพื่อให้..
html`<p title="${title}">Hello ${you}!</p>`
จะแสดงผลสตริงที่มีการแทนที่ตัวแปรที่เหมาะสม แต่จะแทนที่อักขระทั้งหมดที่ไม่ปลอดภัยใน HTML มาเริ่มกันเลย ฟังก์ชันการหลีกเลี่ยง HTML จะใช้อาร์กิวเมนต์ 2 รายการ ได้แก่ ชื่อผู้ใช้และความคิดเห็น ทั้ง 2 อย่างอาจมีอักขระที่ไม่ปลอดภัยใน 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}`;
สรุป
Template Strings อยู่ใน Chrome 41 เบต้าขึ้นไป, IE Tech Preview, Firefox 35 ขึ้นไป และ io.js ในทางปฏิบัติ หากคุณต้องการใช้ฟีเจอร์เหล่านี้ในการผลิตในปัจจุบัน ฟีเจอร์เหล่านี้จะได้รับการรองรับในตัวแปลง ES6 ที่สำคัญ ซึ่งรวมถึง Traceur และ 6to5 ดูตัวอย่างสตริงเทมเพลตในที่เก็บตัวอย่างของ Chrome หากต้องการลองใช้ นอกจากนี้ คุณอาจสนใจเทียบเท่า ES6 ใน ES5 ซึ่งแสดงวิธีใช้สตริงเทมเพลตที่ปรับปรุงแล้วบางส่วนโดยใช้ ES5 ในปัจจุบัน
สตริงเทมเพลตนำความสามารถที่สำคัญมากมายมาสู่ JavaScript ซึ่งรวมถึงวิธีที่ดีกว่าในการทำสตริงและการประมาณค่าของนิพจน์ สตริงหลายบรรทัด และความสามารถในการสร้าง DSL ของคุณเอง
ฟีเจอร์ที่สำคัญที่สุดอย่างหนึ่งที่มาพร้อมกับฟีเจอร์นี้คือเทมเพลตที่ติดแท็ก ซึ่งเป็นฟีเจอร์ที่สำคัญสำหรับการเขียน DSL ดังกล่าว โดยจะรับส่วนของสตริงเทมเพลตเป็นอาร์กิวเมนต์ จากนั้นคุณจะตัดสินใจได้ว่าจะใช้สตริงและการแทนที่อย่างไรเพื่อกำหนดเอาต์พุตสุดท้ายของสตริง