Tạo giá trị riêng biệt với chuỗi mẫu ES6

Addy Osmani
Addy Osmani

Chuỗi trong JavaScript trước đây bị hạn chế, thiếu các chức năng mà người dùng có thể mong đợi từ các ngôn ngữ như Python hoặc Ruby. Chuỗi mẫu ES6 (có trong Chrome 41 trở lên) đã thay đổi điều đó về cơ bản. Các lớp này giới thiệu một cách để xác định chuỗi bằng ngôn ngữ dành riêng cho miền (DSL), mang lại hiệu quả tốt hơn:

  • Nội suy chuỗi
  • Biểu thức được nhúng
  • Chuỗi nhiều dòng không có mã gỡ lỗi
  • Định dạng chuỗi
  • 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 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 gạch chéo ngược (``) thay vì dấu ngoặc đơn hoặc dấu ngoặc 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 cung cấp cho chúng ta gì khác ngoà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 các hàm này 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 biến) và bên trong một Mẫu cố định, kết quả sẽ được xuất ra dưới dạng một phần của cùng một chuỗi.

Chuỗi mẫu có thể chứa phần 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 hoạt động thay thế chuỗi trong Chuỗi mẫu đều là biểu thức JavaScript, nên chúng ta có thể thay thế nhiều nội dung hơn là tên biến. Ví dụ: bên dưới, chúng ta có thể sử dụng tính năng nội suy biểu thức để nhúng một số toán học cùng dòng có thể đọc đượ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.

Các hàm này 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 bạn cần dấu nháy đơn bên trong chuỗi, bạn có thể thoát bằng cách sử dụng ký tự gạch chéo ngược \ như sau:

var greeting = `\`Yo\` World!`;

Chuỗi nhiều dòng

Chuỗi nhiều dòng trong JavaScript đã yêu cầu các giải pháp tạm thời trong một thời gian. Các giải pháp hiện tại cho các vấn đề này yêu cầu các chuỗi phải tồn tại 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ù cách 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 có một chút lỗi. Bạn cũng có thể sử dụng tính năng nối chuỗi để giả mạo tính năng hỗ trợ nhiều dòng, nhưng điều này cũng để lại một số điều cần được mong muốn:

var greeting = "Yo " +
"World";

Chuỗi mẫu đơ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 ở những nơi cần thiết và BOOM. 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à chúng mang lại là mẫu được gắn thẻ. Mẫu được gắn thẻ sẽ biế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ẻ rất khác với ngữ nghĩa của chuỗi mẫu thông thường. Về cơ bản, chúng là một loại lệnh gọi hàm đặc biệt: "đơn giản hoá" ở 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 hoạt động thay thế diễn ra giữa mục thứ n và mục thứ (n + 1) trong mảng chuỗi. Điều này có thể hữu ích cho mọi thứ, nhưng một trong những điều đơn giản nhất là tự động thoát khỏi mọi biến nội suy.

Ví dụ: bạn có thể viết một hàm thoát HTML như sau..

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 cho 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à nhận xét là "& is a fun tag", thì chúng ta sẽ xuất ra:

<b>Domenic Denicola says:</b> "&amp; is a fun tag"

Do đó, giải pháp mẫu được gắn thẻ của chúng ta có thể được viết 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 = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        "'": '&#39;',
        '"': '&quot;'
    },
    oUnescape = {
        '&amp;': '&',
        '&#38;': '&',
        '&lt;': '<',
        '&#60;': '<',
        '&gt;': '>',
        '&#62;': '>',
        '&apos;': "'",
        '&#39;': "'",
        '&quot;': '"',
        '&#34;': '"'
    },
    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>: "&amp; is a fun tag"

Các cách sử dụng khác có thể bao gồm tự động thoát, định dạng, bản địa hoá và nói chung là các hoạt động 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

Chuỗi mẫu có trong Chrome 41 beta trở lên, Bản dùng thử công nghệ IE, 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 phiên bản chính thức hiện nay, thì các tính năng này được hỗ trợ trong các Trình chuyển đổi ES6 chính, bao gồm Traceur và 6to5. Hãy xem mẫu Chuỗi mẫu của chúng tôi trên 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 Các tính năng tương đương ES6 trong ES5. Bài viết này minh hoạ cách đạt được một số tính năng của Chuỗi mẫu đơn giản bằng cách sử dụng ES5 hiện nay.

Chuỗi mẫu mang lại nhiều chức năng quan trọng cho JavaScript. Các tính năng này bao gồm các cách tốt hơ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 các DSL như vậy. Các hàm này nhận các phần của Chuỗi mẫu làm đối số, sau đó bạn có thể quyết định cách sử dụng các chuỗi và tham số thay thế để xác định kết quả cuối cùng của chuỗi.

Tài liệu đọc thêm