Các chuỗi trong JavaScript từ trước đến nay vẫn bị hạn chế, thiếu những chức năng mà người dùng có thể mong đợi khi sử dụng các ngôn ngữ như Python hoặc Ruby. Chuỗi mẫu ES6 (có trong Chrome 41 trở lên) thay đổi cơ bản điều đó. Chúng giới thiệu một cách xác định các chuỗi bằng ngôn ngữ dành riêng cho miền (DSL), mang lại những lợi ích sau:
- Nội suy chuỗi
- Biểu thức được nhúng
- Chuỗi nhiều dòng mà không cần giải pháp tạm thời
- Định dạng chuỗi
- Tính năng gắn thẻ chuỗi để thoát HTML an toàn, bản địa hoá và nhiều tính năng khác.
Thay vì nhồi nhét thêm một tính năng khác vào Chuỗi như chúng ta biết ngày nay, Chuỗi mẫu giới thiệu một cách hoàn toàn khác để giải quyết những vấn đề này.
Cú pháp
Chuỗi mẫu sử dụng dấu nháy ngược (``) thay vì dấu nháy đơn hoặc dấu nháy kép mà chúng ta thường dùng với các chuỗi thông thường. Do đó, bạn có thể viết một chuỗi mẫu như sau:
var greeting = `Yo World!`;
Cho đến nay, Chuỗi mẫu chưa mang lại cho chúng ta điều gì hơn so với chuỗi thông thường. Hãy thay đổi điều đó.
Thay thế chuỗi
Một trong những lợi ích thực sự đầu tiên của chúng là thay thế chuỗi. Tính năng thay thế cho phép chúng ta lấy bất kỳ biểu thức JavaScript hợp lệ nào (bao gồm cả việc thêm các biến) và bên trong một Chuỗi mẫu, kết quả sẽ được xuất ra dưới dạng một phần của cùng một chuỗi.
Template Strings có thể chứa các trình giữ chỗ để thay thế chuỗi bằng cú pháp ${ }, như minh hoạ dưới đây:
// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);
// => "Yo, Brendan!"
Vì tất cả các chuỗi thay thế trong Chuỗi mẫu đều là biểu thức JavaScript, nên chúng ta có thể thay thế nhiều hơn tên biến. Ví dụ: bên dưới, chúng ta có thể dùng tính năng nội suy biểu thức để nhúng cho một số phép toán nội dòng dễ đọc:
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.
Chúng cũng rất hữu ích cho các hàm bên trong biểu thức:
function fn() { return "I am a result. Rarr"; }
console.log(`foo ${fn()} bar`);
//=> foo I am a result. Rarr bar.
${} hoạt động tốt với mọi loại biểu thức, bao gồm cả biểu thức thành phần và lệnh gọi phương thức:
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
Nếu cần dấu nháy ngược trong chuỗi, bạn có thể thoát dấu nháy ngược bằng cách sử dụng ký tự dấu gạch chéo ngược \ như sau:
var greeting = `\`Yo\` World!`;
Chuỗi nhiều dòng
Các chuỗi nhiều dòng trong JavaScript đã yêu cầu các giải pháp tạm thời có tính chất "hack" trong một thời gian. Các giải pháp hiện tại cho phép các chuỗi nằm trên một dòng hoặc được chia thành các chuỗi nhiều dòng bằng cách sử dụng \ (dấu gạch chéo ngược) trước mỗi dòng mới. Ví dụ:
var greeting = "Yo \
World";
Mặc dù điều này sẽ hoạt động tốt trong hầu hết các công cụ JavaScript hiện đại, nhưng bản thân hành vi này vẫn là một thủ thuật. Bạn cũng có thể dùng tính năng nối chuỗi để giả lập chế độ hỗ trợ nhiều dòng, nhưng cách này cũng không được như ý:
var greeting = "Yo " +
"World";
Chuỗi mẫu giúp đơn giản hoá đáng kể các chuỗi nhiều dòng. Bạn chỉ cần thêm dòng mới vào nơi cần thiết và BÙM. Ví dụ:
Mọi khoảng trắng bên trong cú pháp dấu nháy ngược cũng sẽ được coi là một phần của chuỗi.
console.log(`string text line 1
string text line 2`);
Mẫu được gắn thẻ
Cho đến nay, chúng ta đã xem xét việc sử dụng Chuỗi mẫu để thay thế chuỗi và tạo chuỗi nhiều dòng. Một tính năng mạnh mẽ khác mà các mẫu này mang lại là mẫu được gắn thẻ. Tagged Template (Mẫu được gắn thẻ) chuyển đổi một Chuỗi mẫu bằng cách đặt tên hàm trước chuỗi mẫu. Ví dụ:
fn`Hello ${you}! You're looking ${adjective} today!`
Ngữ nghĩa của chuỗi mẫu được gắn thẻ khác biệt rất nhiều so với ngữ nghĩa của chuỗi mẫu thông thường. Về bản chất, đây là một loại lệnh gọi hàm đặc biệt: "desugars" ở trên thành
fn(["Hello ", "! You're looking ", " today!"], you, adjective);
Lưu ý cách đối số thứ (n + 1) tương ứng với phép thay thế diễn ra giữa mục thứ n và thứ (n + 1) trong mảng chuỗi. Điều này có thể hữu ích cho nhiều việc, nhưng một trong những việc đơn giản nhất là tự động thoát mọi biến được nội suy.
Ví dụ: bạn có thể viết một hàm thoát HTML sao cho...
html`<p title="${title}">Hello ${you}!</p>`
trả về một chuỗi có các biến thích hợp được thay thế, nhưng tất cả các ký tự không an toàn trong HTML đều được thay thế. Hãy làm như vậy. Hàm thoát HTML của chúng ta sẽ nhận hai đối số: tên người dùng và nhận xét. Cả hai đều có thể chứa các ký tự không an toàn trong HTML (cụ thể là ', ", <, > và &). Ví dụ: nếu tên người dùng là "Domenic Denicola" và bình luận là "& là một thẻ thú vị", chúng ta nên xuất ra:
<b>Domenic Denicola says:</b> "& is a fun tag"
Do đó, bạn có thể viết giải pháp mẫu được gắn thẻ của chúng tôi như sau:
// 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"
Các trường hợp sử dụng khác có thể có bao gồm tự động thoát, định dạng, bản địa hoá và nói chung là các phép thay thế phức tạp hơn:
// 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}`;
Tóm tắt
Template Strings có trong Chrome 41 beta trở lên, IE Tech Preview, Firefox 35 trở lên và io.js. Trên thực tế, nếu bạn muốn sử dụng các tính năng này trong quá trình sản xuất ngay hôm nay, thì chúng được hỗ trợ trong các Trình chuyển đổi ES6 chính, bao gồm cả Traceur và 6to5. Hãy xem mẫu Chuỗi mẫu của chúng tôi trong kho lưu trữ mẫu Chrome nếu bạn muốn dùng thử. Bạn cũng có thể quan tâm đến ES6 Equivalents in ES5 (Tương đương ES6 trong ES5). Bài viết này minh hoạ cách đạt được một số chuỗi mẫu tạo đường cú pháp bằng cách sử dụng ES5 ngay hôm nay.
Chuỗi mẫu mang đến nhiều chức năng quan trọng cho JavaScript. Những tính năng này bao gồm các cách hiệu quả hơn để thực hiện nội suy chuỗi và biểu thức, chuỗi nhiều dòng và khả năng tạo DSL của riêng bạn.
Một trong những tính năng quan trọng nhất mà chúng mang lại là các mẫu được gắn thẻ – một tính năng quan trọng để tạo ra các DSL như vậy. Chúng nhận các phần của một Chuỗi mẫu làm đối số và sau đó bạn có thể quyết định cách sử dụng các chuỗi và giá trị thay thế để xác định đầu ra cuối cùng của chuỗi.