สตริงใน 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";
สตริงเทมเพลตช่วยให้สตริงหลายบรรทัดทำงานได้ง่ายขึ้นมาก เพียงใส่บรรทัดใหม่ในตำแหน่งที่ต้องการ แล้วทุกอย่างก็เรียบร้อย เช่น
พื้นที่ว่างภายในไวยากรณ์เครื่องหมายแบ็กทิกจะถือว่าเป็นส่วนหนึ่งของสตริงด้วย
console.log(`string text line 1
string text line 2`);
เทมเพลตที่ติดแท็ก
จนถึงตอนนี้ เราได้ดูการใช้สตริงเทมเพลตสำหรับการแทนที่สตริงและการสร้างสตริงหลายบรรทัด ฟีเจอร์ที่มีประสิทธิภาพอีกอย่างหนึ่งคือเทมเพลตที่ติดแท็ก เทมเพลตที่ติดแท็กจะเปลี่ยนรูปแบบสตริงเทมเพลตโดยวางชื่อฟังก์ชันไว้ก่อนสตริงเทมเพลต เช่น
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 ของเราจะใช้อาร์กิวเมนต์ 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}`;
สรุป
สตริงเทมเพลตมีอยู่ใน Chrome 41 เบต้าขึ้นไป, IE Tech Preview, Firefox 35 ขึ้นไป และ io.js ในทางปฏิบัติ หากคุณต้องการใช้ฟีเจอร์เหล่านี้ในเวอร์ชันที่ใช้งานจริงในปัจจุบัน ฟีเจอร์เหล่านี้จะได้รับการรองรับใน Transpiler หลักของ ES6 ซึ่งรวมถึง Traceur และ 6to5 ดูตัวอย่างสตริงเทมเพลตในรีโปตัวอย่างของ Chrome หากต้องการลองใช้ คุณอาจสนใจรายการเทียบเท่าของ ES6 ใน ES5 ซึ่งแสดงวิธีใช้ Template String รูปแบบต่างๆ โดยใช้ ES5 ในปัจจุบัน
สตริงเทมเพลตจะเพิ่มความสามารถที่สำคัญหลายอย่างให้กับ JavaScript ซึ่งรวมถึงวิธีที่ดียิ่งขึ้นในการแทรกสตริงและนิพจน์ สตริงหลายบรรทัด และความสามารถในการสร้าง DSL ของคุณเอง
ฟีเจอร์ที่สําคัญที่สุดอย่างหนึ่งที่มาพร้อมกับเทมเพลตที่ติดแท็กคือฟีเจอร์สําคัญสําหรับการเขียน DSL ดังกล่าว โดยจะได้รับส่วนของสตริงเทมเพลตเป็นอาร์กิวเมนต์ จากนั้นคุณก็เลือกวิธีใช้สตริงและการแทนที่เพื่อกำหนดเอาต์พุตสุดท้ายของสตริงได้