الحصول على الحرفية باستخدام سلاسل نماذج ES6

كانت السلاسل في 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`);

نماذج العلامات

لقد تناولنا حتى الآن استخدام Template Strings لاستبدال السلاسل ولإنشاء سلاسل متعددة الأسطر. ومن الميزات الفعّالة الأخرى التي توفّرها هذه المنصات هي القوالب التي تمّت الإشارة إليها. تحوّل النماذج الموسومة سلسلة النموذج من خلال وضع اسم دالة قبل سلسلة النموذج. على سبيل المثال:

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" والتعليق هو "& هي علامة ممتعة"، يجب أن يكون الناتج كما يلي:

<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 والإصدارات الأحدث، والإصدار التجريبي التقني من Internet Explorer، والإصدار 35 من Firefox والإصدارات الأحدث، وio.js. من الناحية العملية، إذا أردت استخدامها في الإنتاج اليوم، ستجد أنّها متوافقة مع أدوات تحويل الترميز الرئيسية في ES6، بما في ذلك Traceur و6to5. يمكنك الاطّلاع على نموذج سلاسل النماذج في مستودع نماذج Chrome إذا أردت تجربتها. قد يهمّك أيضًا ES6 Equivalents in ES5، الذي يوضّح كيفية تحقيق بعض الميزات التي توفّرها سلاسل القوالب باستخدام ES5 اليوم.

توفّر سلاسل النماذج العديد من الإمكانات المهمة للغة JavaScript. وتشمل هذه الميزات طرقًا أفضل لتضمين السلاسل والعبارات، والسلاسل المتعددة الأسطر، وإمكانية إنشاء لغات خاصة بالمجال.

ومن أهم الميزات التي توفّرها هي النماذج الموسومة، وهي ميزة أساسية لإنشاء مثل هذه اللغات الخاصة بالمجال. تتلقّى هذه الدوال أجزاء من سلسلة النموذج كمعلَمات، ويمكنك بعد ذلك تحديد كيفية استخدام السلاسل وعمليات الاستبدال لتحديد الناتج النهائي للسلسلة.

محتوى إضافي للقراءة