دریافت واقعی با رشته های الگو ES6

آدی عثمانی
Addy Osmani

رشته‌ها در جاوا اسکریپت از نظر تاریخی محدود بوده‌اند و فاقد قابلیت‌هایی هستند که می‌توان از زبان‌هایی مانند پایتون یا روبی انتظار داشت. رشته‌های قالب ES6 (موجود در کروم ۴۱ و بالاتر)، اساساً آن را تغییر می‌دهد. آنها راهی برای تعریف رشته‌ها با زبان‌های خاص دامنه (DSL) معرفی می‌کنند که بهتر می‌شود:

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

به جای اضافه کردن یک ویژگی دیگر به رشته ها همانطور که امروزه آنها را می شناسیم، رشته های قالب روشی کاملا متفاوت برای حل این مشکلات معرفی می کند.

نحو

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

var greeting = `Yo World!`;

تا کنون، رشته های قالب چیزی بیشتر از رشته های معمولی به ما نداده اند. بیایید آن را تغییر دهیم.

تعویض رشته

یکی از اولین مزایای واقعی آنها جایگزینی رشته است. جایگزینی به ما این امکان را می دهد که هر عبارت معتبر جاوا اسکریپت را (از جمله اضافه کردن متغیرها) بگیریم و در داخل یک Template Literal، نتیجه به عنوان بخشی از همان رشته خروجی خواهد شد.

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

// 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";

رشته های الگو به طور قابل توجهی رشته های چند خطی را ساده می کنند. به سادگی خطوط جدید را در جایی که مورد نیاز است قرار دهید و BOOM کنید. در اینجا یک مثال است:

هر فضای خالی در داخل نحو بکتیک نیز بخشی از رشته در نظر گرفته می شود.

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

<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 های خود می باشد.

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

بیشتر خواندن