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

آدي عثمانية
آدي عثمانية

كانت السلاسل في JavaScript محدودة تاريخيًا، لأنّها تفتقر إلى الإمكانيات التي من المتوقّع أن تكون مصدرها لغات مثل Python أو Ruby. ES6 سلاسل النماذج (متاحة في الإصدار 41 من Chrome والإصدارات الأحدث)، تغيّر ذلك بشكلٍ أساسي. حيث تقدم طريقة لتعريف السلاسل بلغات خاصة بالمجال (DSL)، مما يجعل:

  • إقحام السلسلة
  • التعبيرات المضمّنة
  • سلاسل متعددة الأسطر بدون نصائح
  • تنسيق السلسلة
  • وضع علامات على السلاسل لتخطي HTML الآمن والأقلمة والمزيد.

بدلاً من حشو ميزة أخرى في سلاسل كما نعرفها اليوم، تقدم سلاسل النماذج طريقة مختلفة تمامًا لحل هذه المشكلات.

البنية

تستخدم سلاسل النماذج علامات عليا مائلة (``) بدلاً من علامات الاقتباس المفردة أو المزدوجة التي اعتدت عليها مع السلاسل العادية. وبالتالي، يمكن كتابة سلسلة النموذج على النحو التالي:

var greeting = `Yo World!`;

حتى الآن، لم تقدم لنا سلاسل النماذج أي شيء أكثر من ما تفعله السلاسل العادية. لنغير ذلك.

استبدال السلسلة

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

يمكن أن تحتوي سلاسل النموذج على عناصر نائبة لاستبدال السلسلة باستخدام بنية ${ }، كما هو موضّح أدناه:

// 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`);

النماذج التي تم وضع علامات عليها

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

fn`Hello ${you}! You're looking ${adjective} today!`

تختلف دلالات سلسلة النموذج ذات العلامات كثيرًا عن دلالات السلسلة العادية. وهي في جوهرها نوعًا خاصًا من استدعاء الدوال: ما سبق ذكره "Deugars" في

fn(["Hello ", "! You're looking ", " today!"], you, adjective);

لاحظ كيف تتجاوب الوسيطة (n + 1)th مع الاستبدال الذي يحدث بين الإدخالين nth و (n + 1) في صفيف السلسلة. يمكن أن يكون هذا مفيدًا لجميع أنواع الأشياء، ولكن أحد الطرق الأكثر سهولة هو الإفلات التلقائي لأي متغيرات يتم إضافتها.

على سبيل المثال، يمكنك كتابة دالة استبعاد HTML مثل ذلك.

html`<p title="${title}">Hello ${you}!</p>`

سلسلة مع استبدال المتغيرات المناسبة بها، ولكن مع استبدال جميع أحرف HTML غير الآمنة. لنقم بذلك. ستستخدم دالة استبعاد HTML وسيطتين: اسم مستخدم وتعليق. يمكن أن يحتوي كلاهما على أحرف غير آمنة بتنسيق HTML (وهي ' و" و< و> و&). على سبيل المثال، إذا كان اسم المستخدم "Domenic Denicola" وكان التعليق "& is a custom 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}`;

ملخّص

تكون سلاسل النماذج في الإصدار التجريبي 41 من Chrome والإصدارات الأحدث، ومعاينة IE Tech وFirefox 35 والإصدارات الأحدث وio.js. من الناحية العملية، إذا كنت تريد استخدام هذه الأدوات في مرحلة الإنتاج حاليًا، يمكنك استخدام هذه الأدوات في برامج الترجمة من ES6 الرئيسية، بما في ذلك Traceur و6to5. يمكنك الاطّلاع على نموذج سلاسل النماذج على مستودع نماذج Chrome إذا كنت ترغب في تجربتها. قد يهمّك أيضًا الاطّلاع على مكافئات ES6 في ES5، والتي توضّح كيفية تحقيق بعض سلاسل نماذج إضافة السكر التي تجلبها باستخدام ES5 اليوم.

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

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

قراءات إضافية