ثلاث طرق لكتابة السلاسل النصية في JavaScript
توفّر لك JavaScript ثلاثة محدِّدات للسلاسل النصية. اثنان منها متبادلان تمامًا، أما الثالث فيقدّم لك ما هو أكثر من مجرد احتواء النص.
علامات التنصيص المفردة والمزدوجة تُنتج نفس السلسلة النصية تمامًا — اختر واحدة والتزم بها (معظم المشاريع الحديثة تعتمد على المفردة افتراضيًا، أو تترك الأمر لأداة التنسيق). أما backticks فتُنتج ما يُعرف بـ template literal، وهنا يبدأ الجزء الممتع: فهي تسمح بحقن المتغيرات داخل النص وبكتابة نص متعدد الأسطر.
خلف الكواليس، الأنواع الثلاثة تُنتج نفس نوع السلسلة النصية الأولي. فاختيار المحدِّد مجرد مسألة شكلية لا أكثر.
تسلسلات الهروب وتضمين علامات التنصيص
داخل أي سلسلة نصية، الشرطة المائلة العكسية \ تبدأ تسلسل هروب. أشهرها: \n (سطر جديد)، و\t (مسافة جدولة)، و\\ (شرطة مائلة عكسية فعلية)، إضافة إلى \" و\' لتضمين نفس نوع علامة التنصيص التي افتتحت بها السلسلة:
يمكنك الاستغناء عن معظم محارف الـ escape بمجرد اختيار نوع الاقتباس الآخر: العبارة 'She said "hi" and left.' لا تحتاج أي backslashes. المرونة أفضل من التعصب للقواعد.
template literals في جافا سكريبت: قوة الـ backtick الخفية
الـ template literal يقدّم لك ميزتين لا تجدهما في السلاسل النصية العادية. أولاً، يتيح لك حقن المتغيرات داخل النص عبر ${...}:
كل ما يوجد داخل ${...} هو تعبير (expression) في JavaScript، وليس مجرد اسم متغير. فيمكنك كتابة عمليات حسابية، أو استدعاء دوال، أو استخدام الشرط الثلاثي (ternary)، بل حتى template literals أخرى متداخلة — كل ذلك مسموح:
ثانيًا، تدعم الـ template literals في جافا سكريبت كتابة نص متعدد الأسطر دون الحاجة إلى \n:
الأسطر الجديدة داخل النص المصدر تُحفظ كما هي في السلسلة الناتجة. ولهذا السبب، إذا كنت تتعامل مع أي نص أطول من مجرد كلمة أو عنوان صغير، فالـ backtick هو الخيار الصحيح في معظم الأحيان.
حقن المتغيرات في النصوص أفضل من الدمج اليدوي
قبل ظهور template literals في جافا سكريبت، كانت الطريقة الوحيدة لبناء سلسلة نصية ديناميكية هي استخدام معامل الجمع +:
كلا الأسلوبين يعطي نفس الناتج. فرق template literals في جافا سكريبت إنها تُقرأ زي الجملة اللي تبنيها فعلاً، بينما طريقة + تجبرك تتابع علامات التنصيص والمسافات وعلامات الدمج وحدة وحدة. استخدم + فقط لما تضيف شيء صغير لنص موجود. أما لو النص أطول من كذا، روح مباشرة للـ backtick.
السلاسل النصية غير قابلة للتعديل
كل دالة تبدو وكأنها تعدّل على السلسلة النصية، هي في الحقيقة ترجّع سلسلة جديدة:
إذا أردت أن يحدث التغيير فعلاً، لازم تُسنِد الناتج إلى متغير. هذه النقطة تُوقِع المبتدئين في فخ شائع: يكتبون s.replace("a", "b") ويتوقعون أن قيمة s ستتغير، لكن هذا لا يحدث. السلاسل النصية في javascript تتصرف مثل الأرقام تماماً: القيمة نفسها لا يمكن تعديلها، كل ما يمكنك فعله هو توجيه المتغير إلى قيمة جديدة.
دوال النصوص في javascript التي ستستخدمها فعلاً
واجهة السلاسل النصية في javascript ضخمة ومليئة بالدوال، لكن في الواقع اليومي ستجد نفسك تعتمد على حفنة صغيرة منها فقط:
بعض النقاط التي يستحسن حفظها:
lengthخاصية وليست دالة — بدون أقواس.replaceمع نص عادي يستبدل أول تطابق فقط. لاستبدال جميع المطابقات استخدمreplaceAllأو تعبيرًا نمطيًا مع الرايةg.slice(start, end)يأخذ مجالًا نصف مفتوح: الحرف عندendغير مُضَمَّن.- الفهارس السالبة في
sliceتُحسب من النهاية:s.slice(-3)يُرجع آخر ثلاثة أحرف.
الفهرسة والمرور على أحرف النص
تتصرف السلاسل النصية في javascript وكأنها مصفوفات أحرف للقراءة فقط. يمكنك الوصول إلى أي حرف عبر فهرسه والمرور على الأحرف واحدًا تلو الآخر، لكن لا يمكنك تعديل حرف في موضع معيّن:
for...of يمرّ على نقاط الترميز (code points)، وهذا يتعامل مع معظم محارف يونيكود بشكل صحيح. أما الوصول عبر الفهرس (s[i]) فيمرّ على وحدات ترميز UTF-16، وقد يقطع الإيموجي والمحارف خارج نطاق BMP نصفين. في النصوص العادية كلا الأسلوبين يفي بالغرض، لكن مع أي محتوى يُدخله المستخدم، يُفضَّل استخدام for...of أو [...s].
Tagged Template Literals في javascript
يبقى شكل أخير يستحق المعرفة، حتى لو لم تكتبه كثيرًا. الـ tagged template literal عبارة عن استدعاء لدالة تمرَّر إليها أجزاء النص الثابتة والقيم المحقونة كمعاملات منفصلة:
الدالة الوسم (tag function) هي اللي تقرر شكل النص النهائي — ممكن تستخدمها لتهريب HTML، أو بناء استعلامات SQL بشكل آمن، أو توليد CSS، أو تحليل GraphQL. راح تشوف هذا النمط في مكتبات مثل styled-components وgraphql-tag وlit-html أكثر بكثير من احتياجك لكتابته بنفسك. لكن لما تحتاج معالجة نصية مخصصة، الـ tagged templates هي أنظف أداة للمهمة.
أخطاء شائعة ينبغي الانتباه لها
قائمة مختصرة بالأشياء اللي يتعثر فيها الكثيرون:
- نسيان إسناد نتيجة التابع.
s.trim()لا يفعل شيئًا لوحده، لازم تسند الناتج لمتغير. - استخدام
+لدمج رقم مع نص. نتيجة"Age: " + 30 + 5هي"Age: 305"وليست"Age: 35". الـ template literals تتجنب هذه المشكلة:`Age: ${30 + 5}`. - الخلط بين
==ومقارنة النصوص. راح نغطي موضوع المساواة بتفصيل لاحقًا، لكن"1" == 1تعطيtrueبينما"1" === 1تعطيfalse. فضّل استخدام===دائمًا. - افتراض أن
lengthيساوي عدد الأحرف. مع الإيموجي وغيرها من المحارف التي تستخدم surrogate pairs، قيمة"🙂".lengthهي 2 وليست 1. استخدم[..."🙂"].lengthأوArray.from(s).lengthلما تحتاج عدد المحارف كما يراها المستخدم.
التالي: الأرقام و BigInt
النصوص نوع واحد من الأنواع البدائية، والأرقام نوع آخر. نظام الأرقام في جافا سكريبت له خصوصياته الغريبة — نوع Number واحد يشمل الأعداد الصحيحة والعشرية معًا، إضافةً إلى BigInt للحالات التي لا يكفي فيها ذلك. وهذا موضوع الصفحة التالية.
الأسئلة الشائعة
ما الفرق بين علامات التنصيص والـ backticks في JavaScript؟
علامتا التنصيص المفردة (') والمزدوجة (") تُنشئان سلسلة نصية عادية، وهما متبادلتان تماماً. أما الـ backticks (`) فتُنشئ ما يُعرف بالـ template literals، وتدعم حقن القيم عبر ${...} وكتابة النص على عدة أسطر دون الحاجة لرموز الهروب. القاعدة البسيطة: استخدم الـ backticks كلما احتجت إلى إدراج متغيّر أو كتابة نص يمتد على أكثر من سطر.
كيف أُدرج متغيّراً داخل نص في JavaScript؟
الطريقة الأنظف هي استخدام template literal: ضع النص بين علامتي backtick واكتب التعبير داخل ${...}. مثلاً `Hello, ${name}!` يُقيّم name ويضع قيمته مكانه. ويمكنك وضع أي تعبير بالداخل: ${a + b} أو ${user.name.toUpperCase()}، بل حتى template literal آخر متداخل.
هل السلاسل النصية في JavaScript غير قابلة للتعديل (immutable)؟
نعم، وهذه نقطة مهمة. كل دوال النصوص مثل toUpperCase وslice وreplace تُرجع سلسلة جديدة ولا تُعدّل الأصلية. فلو كتبت s.toUpperCase() دون إسناد الناتج إلى متغيّر، فلن يتغيّر شيء. المبدأ نفسه موجود في Python وJava.
ما هي الـ tagged template literals؟
الـ tagged template literal يسمح لك بتمرير محتوى القالب إلى دالة تستقبل الأجزاء النصية والقيم المحقونة كمعاملات منفصلة. فمثلاً tag`Hello, ${name}` يُترجم إلى استدعاء tag(["Hello, ", ""], name). مكتبات مثل styled-components وgraphql-tag تعتمد على هذه الفكرة لتحليل القالب أو تحويله قبل إنتاج القيمة النهائية.