دریافت حروف با رشته‌های الگوی ES6

رشته‌ها در جاوا اسکریپت ازنظر تاریخی محدود بوده‌اند و قابلیت‌هایی را که ممکن است از زبان‌هایی مانند Python یا Ruby انتظار داشته باشید، نداشته‌اند. ‫ES6 رشته‌های الگو (در Chrome 41 و نسخه‌های بالاتر دردسترس است) این وضعیت را اساساً تغییر می‌دهد. این ویژگی روشی برای تعریف رشته‌ها با زبان‌های مختص دامنه (DSLs) ارائه می‌دهد که باعث بهبود موارد زیر می‌شود:

  • درون‌یابی رشته
  • عبارت‌های جاسازی‌شده
  • رشته‌های چندخطی بدون ترفند
  • قالب‌بندی رشته
  • برچسب‌گذاری رشته برای گریز ایمن HTML، بومی‌سازی، و غیره.

به‌جای اینکه ویژگی دیگری را به «رشته‌ها» (Strings) که امروزه می‌شناسیم اضافه کنیم، «رشته‌های الگو» (Template Strings) روش کاملاً متفاوتی برای حل این مشکلات ارائه می‌دهند.

نحو

«رشته‌های الگو» به‌جای نقل‌قول‌های تکی یا دوتایی که در رشته‌های معمولی استفاده می‌کنیم، از علامت‌های نقل‌قول معکوس (``) استفاده می‌کنند. بنابراین، رشته الگو می‌تواند به‌صورت زیر نوشته شود:

var greeting = `Yo World!`;

تاکنون، «رشته‌های الگو» چیزی بیشتر از رشته‌های معمولی به ما نداده‌اند. بیایید این را تغییر دهیم.

جایگزینی رشته

یکی از اولین مزایای واقعی آن‌ها جایگزینی رشته است. جایگزینی به ما امکان می‌دهد هر عبارت معتبر جاوا اسکریپت (ازجمله، مثلاً، افزودن متغیرها) را بگیریم و در «حرفی الگویی»، نتیجه به‌عنوان بخشی از همان رشته برونداد خواهد شد.

«رشته‌های الگو» می‌توانند حاوی جای‌بان‌هایی برای جایگزینی رشته بااستفاده از نحو ${ } باشند، همان‌طور که در زیر نشان داده شده است:

// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);

// => "Yo, Brendan!"

ازآنجایی‌که همه جایگزینی‌های رشته‌ای در «رشته‌های الگو» عبارت‌های جاوا اسکریپت هستند، می‌توانیم موارد بسیار بیشتری از نام‌های متغیر را جایگزین کنیم. برای مثال، در زیر می‌توانیم از میان‌یابی عبارت برای جاسازی برخی‌از ریاضیات خوانا درخط استفاده کنیم:

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!`;

رشته‌های چندخطی

رشته‌های چندخطی در جاوا اسکریپت مدت‌ها است که به راهکارهای دور زدن پیچیده نیاز دارند. راه‌حل‌های کنونی برای آن‌ها مستلزم این است که رشته‌ها یا در یک خط باشند یا بااستفاده از \ (خط مورب معکوس) قبل‌از هر خط جدید به رشته‌های چندخطی تقسیم شوند. برای مثال:

var greeting = "Yo \
World";

اگرچه این روش در اکثر موتورهای مدرن جاوا اسکریپت به‌خوبی کار می‌کند، اما خود رفتار همچنان کمی غیرمعمول است. همچنین می‌توان از الحاق رشته برای جعل پشتیبانی چندخطی استفاده کرد، اما این روش نیز مطلوب نیست:

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 ما دو آرگومان می‌گیرد: نام کاربری و نظر. هر دو ممکن است حاوی نویسه‌های ناامن HTML باشند (یعنی '، "، <، >، و &). برای مثال، اگر نام کاربری «Domenic Denicola» و نظر «& is a fun tag» باشد، باید این برونداد را داشته باشیم:

<b>Domenic Denicola says:</b> "&amp; 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 = {
        '&': '&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"

کاربردهای احتمالی دیگر شامل خودکارسازی، قالب‌بندی، بومی‌سازی، و به‌طورکلی جایگزینی‌های پیچیده‌تر می‌شود:

// 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 beta+‎،‏ IE Tech Preview،‏ Firefox 35+‎، و io.js دردسترس است. از نظر عملی، اگر می‌خواهید امروز از آن‌ها در تولید استفاده کنید، در ترانسپایلرهای اصلی ES6، ازجمله Traceur و 6to5 پشتیبانی می‌شوند. اگر می‌خواهید آن‌ها را امتحان کنید، نمونه رشته‌های الگو را در مخزن نمونه‌های Chrome بررسی کنید. همچنین ممکن است به معادل‌های ES6 در ES5 علاقه‌مند باشید که نشان می‌دهد چگونه می‌توان برخی‌از شیرین‌سازی‌های «رشته‌های الگو» را بااستفاده از ES5 امروزه به‌دست آورد.

«رشته‌های الگو» قابلیت‌های مهم بسیاری را به «جاوا اسکریپت» می‌آورند. این موارد شامل روش‌های بهتر برای انجام درون‌یابی رشته و عبارت، رشته‌های چندخطی، و توانایی ایجاد زبان‌های دامنه خاص خودتان است.

یکی از مهم‌ترین ویژگی‌هایی که ارائه می‌دهند الگوهای برچسب‌گذاری‌شده است - ویژگی‌ای حیاتی برای ساختن چنین DSLهایی. آن‌ها بخش‌های «رشته الگو» را به‌عنوان آرگومان دریافت می‌کنند و سپس می‌توانید تصمیم بگیرید که چگونه از رشته‌ها و جایگزینی‌ها برای تعیین برونداد نهایی رشته‌تان استفاده کنید.

مطالعه بیشتر