برنامج جافا سكريبت عبارة عن سلسلة من الجُمل
أي برنامج مكتوب بلغة جافا سكريبت ما هو إلا قائمة من الجُمل (statements)، أي تعليمات يقوم المحرّك بتنفيذها واحدة تلو الأخرى من الأعلى إلى الأسفل. فتعريف متغيّر جملة، واستدعاء دالّة جملة، وكتلة if أو for جملة أيضًا. ويتمّ الفصل بين هذه الجُمل باستخدام الفاصلة المنقوطة.
ثلاث جُمَل، وثلاث فواصل منقوطة. المحرّك ينفّذ الأولى، ثم الثانية، ثم الثالثة. الأمر بهذه البساطة.
المسافات البيضاء والمحاذاة لا تعني شيئًا للمُحلِّل اللغوي (Parser). يمكنك وضع الجُمَل الثلاث في سطر واحد مفصولة بفواصل منقوطة، وستعمل بنفس الطريقة تمامًا. نحن نستخدم المحاذاة من أجل القارئ البشري، لا من أجل المحرّك.
الكُتَل تجمع الجُمَل معًا
الأقواس المعقوفة { } تُنشئ ما يُسمّى كُتلة (Block) — وهي مجموعة من الجُمَل يتعامل معها المحرّك كوحدة واحدة. ستصادف الكُتَل في كل مكان: أجسام الدوال، وفروع if، وأجسام الحلقات.
استدعاءا console.log الموجودان داخل الأقواس المعقوفة يمثّلان جسم جملة if. لاحظ أنه لا توجد فاصلة منقوطة بعد القوس المعقوف الختامي }، فالكتل ليست جملًا تحتاج إلى منهي. جملة if بأكملها تنتهي عند انتهاء الكتلة.
هذه النقطة تُربك كثيرًا من القادمين من لغات يتبع فيها كل } فاصلةٌ منقوطة ;. أما في جافا سكريبت، فالكتلة المستقلة أو كتلة التحكم في التدفق لا تحتاج إلى ذلك.
التعابير مقابل الجمل في جافا سكريبت
من المهم أن تُميّز مبكرًا بين مفهومين أساسيين في صياغة جافا سكريبت: التعابير (expressions) تُنتج قيمة، أما الجمل (statements) فتُنفّذ فعلًا ما.
2 + 3تعبير، وناتج تقييمه هو5.let x = 2 + 3;جملة، فهي تُعرِّف متغيرًا وتُسند إليه ناتج تعبير.console.log("hi")تعبير (لأن استدعاء الدالة يُرجعundefined)، لكنه حين يُكتب وحده في سطر منتهٍ بفاصلة منقوطة يتحوّل إلى جملة تعبيرية (expression statement).
في أغلب الأحيان لن تحتاج للتفكير في هذا الموضوع، لكنه يصبح مهمًا عند التعامل مع الدوال السهمية (arrow functions)، والعامل الثلاثي (ternary)، وفي المواضع التي تتوقع فيها جافا سكريبت تعبيرًا (expression) فتعطيها أنت جملة (statement)، أو العكس.
هل الفاصلة المنقوطة ضرورية في جافا سكريبت؟
الإجابة الصريحة: جافا سكريبت تمتلك ميزة اسمها الإدراج التلقائي للفاصلة المنقوطة (ASI)، وهي تقوم بإضافة الفواصل المنقوطة الناقصة نيابةً عنك عند معظم فواصل الأسطر. وهذا يعني أن كودًا مثل التالي سيعمل دون مشاكل:
بدون فاصلة منقوطة، وبدون أخطاء. آلية الإدراج التلقائي للفاصلة المنقوطة (ASI) تنظر إلى كل سطر جديد وتسأل نفسها: "هل يمكن للرمز التالي أن يكون امتدادًا للجملة الحالية؟" إذا كانت الإجابة لا، فإنها تُدرج فاصلة منقوطة.
بفضل آلية ASI، يوجد أسلوبان شائعان في الكود الحقيقي:
- استخدام الفاصلة المنقوطة دائمًا. هذا هو السائد في معظم المشاريع والدروس وأدلة التنسيق.
- بدون فاصلة منقوطة إطلاقًا. يستخدمه بعض المشاريع الحديثة (مثل أسلوب Standard وبعض مشاريع React)، ويعتمد على آلية ASI مع بعض الحيل الوقائية.
كلا الأسلوبين يعمل بشكل صحيح، ولا يمكن وصف أحدهما بأنه "خاطئ". الخطأ الحقيقي هو عدم الاتساق — فخلط الأسلوبين داخل الملف الواحد يجعل اكتشاف الأخطاء أصعب بكثير.
متى تتسبب آلية ASI في المشاكل؟
تعمل آلية ASI بشكل صحيح في حوالي 99% من الحالات. أما الـ 1% المتبقية فهي تلك الأسطر التي تبدأ برمز يمكن اعتباره امتدادًا للسطر السابق. الرموز المزعجة هي: [ و ( و ` و + و - و /.
تأمل هذا المثال:
من المتوقع أن تتبادل قيمتا x و y، لكن ذلك لا يحدث. السبب أن آلية الإدراج التلقائي للفاصلة المنقوطة (ASI) لا تضيف فاصلة منقوطة قبل [x, y]، لأن التعبير 10[x, y] صحيح نحويًا (يُفسَّر على أنه فهرسة داخل الرقم 10). وبالتالي يقرأ المحلل اللغوي السطر الثاني والسطر الثالث كتعبير واحد طويل، فتحصل على خطأ أثناء التنفيذ أو على نتيجة غير متوقعة.
الحل هو إما وضع فاصلة منقوطة في نهاية السطر الثاني:
أو، إذا كنت تكتب بأسلوب بدون فواصل منقوطة، ضع فاصلة منقوطة في بداية السطر المشبوه:
ذلك ; في بداية السطر هو الحيلة الدفاعية التي تلجأ إليها المشاريع التي لا تستخدم الفاصلة المنقوطة. يبدو الأمر غريبًا حتى تفهم السبب وراءه.
فخ return
هناك حالة واحدة من حالات الإدراج التلقائي للفاصلة المنقوطة تستحق أن تحفظها جيدًا، لأنها تسبّب أخطاء صامتة. إذا وضعت سطرًا جديدًا مباشرة بعد return، فإن آلية ASI تُدرج فاصلة منقوطة في ذلك الموضع، فتُرجع الدالة القيمة undefined:
كان المطوّر يقصد إرجاع كائن، لكنّ آلية الإدراج التلقائي للفاصلة المنقوطة (ASI) رأت كلمة return في نهاية السطر، فأنهت الجملة فورًا عند هذا الحد. والنتيجة أنّ الكائن الحرفي أصبح شيفرة لا يمكن الوصول إليها.
الحل ببساطة هو أن تبدأ القيمة في نفس سطر return:
نفس القاعدة تنطبق على throw وbreak وcontinue وyield — لا تضع سطرًا جديدًا بين الكلمة المفتاحية وقيمتها.
قاعدة بسيطة تنفع دائمًا
إذا كنت مبتدئًا في جافا سكريبت، فإن أسهل طريق هو:
- اكتب الفاصلة المنقوطة بشكل صريح في نهاية كل جملة.
- لا تضعها بعد
}التي تُغلق الكتل فيifوforوwhileوتعريفات الدوال وأجسام الأصناف. - ضعها بعد
}في حالة الكائنات الحرفية (object literal) أو تعبير الدالة (function expression) المُسنَد إلى متغير، مثل:const f = function() {};. - استخدم أداة تنسيق مثل Prettier أو ESLint مع قاعدة أسلوبية، وتوقف عن التفكير في الأمر. الأداة ستفرض ما اتفق عليه فريقك.
هذه القاعدة ليست قانونًا مُقدَّسًا، بل هي الاتفاق الشائع الذي ستراه في غالبية أكواد الجافا سكريبت. التزم بها إلى أن يظهر لك سبب وجيه للخروج عنها.
حساسية حالة الأحرف والمعرِّفات في جافا سكريبت
قاعدتان صغيرتان تندرجان هنا أيضًا:
- جافا سكريبت حسّاسة لحالة الأحرف. يعني
userNameوusernameوUserNameثلاثة معرِّفات مختلفة تمامًا. - يمكن أن تحتوي المعرِّفات على أحرف وأرقام وعلامتَي
_و$، لكن لا يجوز أن تبدأ برقم. كما لا يجوز أن تكون كلمات محجوزة مثلclassأوreturnأوfunction.
علامة $ مسموح بها لغويًا، لكن العُرف جرى على حجزها للمكتبات (استخدمتها jQuery قديمًا، وما زالت بعض أنظمة القوالب تعتمد عليها). نادرًا ما تختارها بنفسك للمتغيرات العادية.
التالي: الوضع الصارم (Strict Mode)
جافا سكريبت الحديثة تعمل بهدوء في نسخة أكثر صرامة من اللغة تُعرف بـ الوضع الصارم، وفيها تتحول بعض التصرفات المتساهلة إلى أخطاء حقيقية. وحدات ES والكلاسات (class bodies) تعمل في هذا الوضع تلقائيًا، لكن من المهم أن تعرف ما الذي يتغير فعليًا — وهذا ما سنتناوله في الصفحة التالية.
الأسئلة الشائعة
هل الفواصل المنقوطة ضرورية في جافا سكريبت؟
من الناحية التقنية لا، لأن جافا سكريبت تحتوي على خاصية الإدراج التلقائي للفاصلة المنقوطة (ASI) التي تضيفها نيابة عنك عند معظم فواصل الأسطر. لكن عملياً، أغلب الفرق تكتبها بشكل صريح لأن ASI لها حالات خاصة تسبب سلوكاً خاطئاً، خاصة عندما يبدأ السطر بـ [ أو ( أو ` أو + أو - أو /. اختر أسلوباً واحداً ودع أداة مثل Prettier تفرضه تلقائياً.
ما هو الإدراج التلقائي للفاصلة المنقوطة (ASI) في جافا سكريبت؟
ASI هي القاعدة التي تسمح لجافا سكريبت بإدراج الفواصل المنقوطة المفقودة في نهاية السطر عندما لا يمكن للرمز التالي أن يكمل الجملة الحالية. لهذا السبب تعمل let x = 1 بدون فاصلة منقوطة. لكنها تفشل عندما يبدأ السطر التالي بشيء يمكن أن يكون امتداداً للسطر السابق، مثل [ أو (، فتقوم جافا سكريبت بدمج السطرين بصمت.
ما الصياغة الأساسية للجملة في جافا سكريبت؟
الجملة هي تعليمة واحدة، سواء كانت تصريح متغير أو استدعاء دالة أو كتلة if أو حلقة تكرار. الجمل تُفصل بينها بفواصل منقوطة (صريحة أو مُدرجة تلقائياً)، وتُجمَّع داخل أقواس { }. المحرك يتجاهل المسافات البيضاء والإزاحات تماماً، فالتنسيق موجود لراحة القارئ البشري لا للمحرك.