قالب النص الحديث في JavaScript

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

قالب النص (Template Literals) هو قالب يحوي السلاسل النصية بالإضافة إلى السماح بكتابة تعبيرات برمجية ضمنه. يمكنك استخدام سلاسل نصيَّة متعدِّدة الأسطر مع ميزات استيفاء السلاسل؛ وكان يسمى "سلاسل القوالب" (template strings) في الإصدارات السابقة من مواصفات ES2015.

الصياغة

`string text`
`string text line 1
 string text line 2`
`string text ${expression} string text`
tag `string text ${expression} string text`

الوصف

يتم إحاطة قالب النص بعلامة اقتباس مائلة (``) بدلاً من علامات اقتباس مزدوجة أو مفردة، ويمكن أن تحتوي على عناصر نائبة (placeholders). يشار إلى هذه العناصر النائبة بواسطة علامة الدولار وأقواس معقوصة بالشكل ‎${expression}‎. يتم تمرير التعابير الموجودة في العناصر النائبة والنص الموجود بين علامتي الاقتباس المائلتين (``) إلى دالة. تقوم هذه الدالة الافتراضية فقط بترتيب الأجزاء في سلسلة واحدة إذا كان هناك تعبير يسبق قالب النص (وهو الوسم tagهنا)، فإن هذا يسمى "القالب الموسوم". في هذه الحالة، يتم استدعاء تعبير الوسم (عادةً ما يكون دالة) باستخدام قالب النص والذي يمكنك معالجته قبل الإخراج، للهروب من الفاصلة العليا المائلة في قالب حرفي ضع شرطة مائلة للخلف \ قبل الفاصلة العليا المائلة.

`\`` === '`' // --> true

نصوص متعددة الأسطر

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

console.log (line text string 1 \ n '+
'Line 2 string text');
// "The text line of string 1
// String line text 2

للحصول على نفس التأثير باستخدام قوالب النصوص الحديثة، يمكنك الآن كتابتها كتابةً طبيعيةً بالشكل التالي:

console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"

تضمين التعابير

لتضمين التعابير ضمن سلسلة نصية، يمكنك استخدام الصيغة التالية:

var a = 5;
var b = 10;
console.log('Fifteen is ' + (a + b) + ' and\nnot ' + (2 * a + b) + '.');
// "Fifteen is 15 and
// not 20."A

الآن، باستخدام القوالب تلك، يمكنك استخدام التجميل اللغوي لعمل استبدالات مثل هذا المثال الذي أصبح سهل القراءة:

var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."

القوالب المتداخلة

في بعض الحالات، يعد تداخل القالب الطريقة الأسهل وربما الطريقة الأفضل للحصول على سلاسل نصية قابلة للتكوين. يمكن ببساطة استخدام قالب داخل قالب آخر باستخدام عنصر نائب ‎${}‎. على سبيل المثال، إذا كانت حالة (شرط) ما صحيحة: فقم بإرجاع هذا القالب النصي.

  • في ES5:
var classes = 'header'
classes += (isLargeScreen() ?
   '' : item.isCollapsed ?
     ' icon-expander' : ' icon-collapser');
  • في ES2015 مع عدم تداخل في القوالب:
const classes = `header ${ isLargeScreen() ? '' :
    (item.isCollapsed ? 'icon-expander' : 'icon-collapser') }`;
  • في ES2015 تداخل في القوالب:
const classes = `header ${ isLargeScreen() ? '' :
 `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;

القوالب الموسومة (tagged templates)

القوالب الموسومة (tagged templates) هي شكل أكثر تقدمًا من القوالب النصية، إذ تتيح لك هذه الوسوم تحليل القالب مع دالة. يحتوي الوسيط الأول من دالة الوسم على مصفوفة من القيم النصية. ترتبط الوسائط المتبقية بالتعابير؛ في النهاية، يمكن أن ترجع دالتك السلسلة النصية المعالجة (أو يمكنها إرجاع شيء مختلف تمامًا كما هو موضح في المثال التالي). يمكن أن يكون اسم الدالة المستخدمة للوسم أي اسم تريده.

var person = 'Mike';
var age = 28;

function myTag(strings, personExp, ageExp) {
  var str0 = strings[0]; // "That "
  var str1 = strings[1]; // " is a "

  // تقنيًا، يوجد سلسلة نصية بعد
  // (التعبير الأخير (في مثالنا
  // ولكنها فارغة ("")، لذا أهملها
  // var str2 = strings[2];

  var ageStr;
  if (ageExp > 99){
    ageStr = 'centenarian';
  } else {
    ageStr = 'youngster';
  }

  // حتى أننا نستطيع إعادة سلسلة نصية مبنية باستعمال قالب نصي
  return `${str0}${personExp}${str1}${ageStr}`;
}

var output = myTag`That ${ person } is a ${ age }`;

console.log(output);
// That Mike is a youngster

الدوال tag لا تحتاج لارجاع سلسلة نصية كما هو موضح في المثال التالي:

function template(strings, ...keys) {
  return (function(...values) {
    var dict = values[values.length - 1] || {};
    var result = [strings[0]];
    keys.forEach(function(key, i) {
      var value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });
    return result.join('');
  });
}

var t1Closure = template`${0}${1}${0}!`;
t1Closure('Y', 'A');  // "YAY!"
var t2Closure = template`${0} ${'foo'}!`;
t2Closure('Hello', {foo: 'World'});  // "Hello World!"

السلاسل النصية الخام (Raw strings)

الخاصية raw المتاحة في الجزئية الأولى للدالة tag، تتيح لك الوصول إلى السلاسل النصية الخام عند إدخالها دون معالجة سلاسل الهروب (escape sequences).

function tag(strings) {
  console.log(strings.raw[0]);
}

tag`string text line 1 \n string text line 2`;
// logs "string text line 1 \n string text line 2" ,
// including the two characters '\' and 'n'

بالإضافة إلى ذلك، يوجد التابع String.raw()‎ لإنشاء السلاسل النصية الخام raw، تمامًا مثل دالة القالب الافتراضية ستقوم بإنشاء سلسلة نصية.

var str = String.raw`Hi\n${2+3}!`;
// "Hi\n5!"

str.length;
// 6

str.split('').join(',');
// "H,i,\,n,5,!"

القوالب الموسومة والسلاسل المُهرَّبة

سلوك ES2016

بدءًا من ECMAScript 2016، تتوافق القوالب الموسومة (tagged templates) مع قواعد السلاسل المُهرَّبة التالية:

  • لتهريب المحارف المرمزة بترميز يونيكود، يجب البدء بـ "‎\u" مثل ‎\u00A9.
  • لتهريب رقم محرف يونيكود (Unicode code point)، يُستعمَل "‎\u{}‎" مثل ‎\u{2F804}‎
  • لتهريب محارف مرمزة بالترميز الست عشري، يجب البدء بـ "‎\x"، مثل ‎\xA9
  • لتهريب محارف مرمزة بالترميز الثماني، يجب البدء بـ "0o\" يتبعها رقم واحد أو أكثر مثل ‎\0o251

هذا يعني ان القالب الموسوم كالذي في المثال التالي يحوي مشكلة، لأنه وفقًا لقواعد ECMAScript، يبحث المُحلل عن ترميز سلسلة محارف يونيكود صالحة لتهريبها وفقاً للقواعد السابقة، لكنه يجد صيغة مشوهة.

latex`\unicode`
// Throws in older ECMAScript versions (ES2016 and earlier)
// SyntaxError: malformed Unicode character escape sequence
ES2018 revision of illegal escape sequences

مراجعة ES2018 لسلاسل تهريب غير مسموح بها

يجب أن تسمح القوالب الموسومة بتضمين لغات مثل (DSLs أو LaTeX)، حيث تكون سلاسل التهريب الآخرى معروفة؛ يزيل مقترح ECMAScript الذي يخص Template Literal Revision صيغة تقييد سلاسل التهريب في ECMAScript من القوالب الموسومة (المرحلة 4، لتكون متكاملة مع معيار ECMAScript 2018).

مع ذلك، سلاسل التهريب غير الصحيحة (illegal escape sequences) لا تزال موجودة في التمثيل المسمى "cooked". ستظهر هذه السلاسل كعنصر undefined (غير معرف) في المصفوفة "cooked" كالتالي:

function latex(str) { 
 return { "cooked": str[0], "raw": str.raw[0] }
} 

latex`\unicode`

// { cooked: undefined, raw: "\\unicode" }

لاحظ أن قيد سلسلة التهريب يتم إسقاطه فقط من القوالب الموسومة، وليس من القوالب غير الموسومة:

let bad = `bad escape sequence: \unicode`;

مصادر ومواصفات