الفصل 00

مقدمة

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

— إلين أولمان، قريب من الآلة: هوس التقنية وعدم رضاها

رسم توضيحي لمفك براغي بجانب لوحة دوائر بحجم مماثل تقريباً

هذا كتاب عن إعطاء التعليمات للحواسيب. الحواسيب اليوم شائعة مثل مفكات البراغي، لكنها أكثر تعقيداً بكثير، وجعلها تفعل ما تريد ليس بالأمر السهل دائماً.

إذا كانت المهمة التي تريدها من حاسوبك مهمة شائعة ومفهومة جيداً، مثل عرض بريدك الإلكتروني أو العمل كآلة حاسبة، فيمكنك فتح التطبيق المناسب والبدء بالعمل. لكن في المهام الفريدة أو المفتوحة، لا يوجد غالباً تطبيق مناسب.

هنا قد تأتي البرمجة. البرمجة هي فعل بناء برنامج — مجموعة من التعليمات الدقيقة التي تخبر الحاسوب بما يفعل. ولأن الحواسيب كائنات بليدة ومتزمتة حرفياً، فإن البرمجة مملة ومحبطة في جوهرها.

لحسن الحظ، إذا تمكنت من تجاوز هذه الحقيقة — وربما حتى الاستمتاع بصرامة التفكير بمصطلحات تستطيع الآلات البليدة التعامل معها — فقد تكون البرمجة مجزية. فهي تتيح لك فعل أشياء في ثوانٍ كانت ستستغرق إلى الأبد يدوياً. وهي طريقة لجعل أداة حاسوبك تفعل أشياء لم تكن تقدر عليها من قبل. وفوق ذلك، إنها لعبة رائعة لحل الألغاز والتفكير المجرد.

معظم البرمجة تُنجز بلغات البرمجة. لغة البرمجة لغة مصطنعة تُستخدم لإعطاء التعليمات للحواسيب. ومن المثير للاهتمام أن أكثر الطرق فعالية التي وجدناها للتواصل مع الحاسوب تستعير بكثافة من طريقة تواصلنا مع بعضنا. فمثل اللغات البشرية، تسمح لغات الحاسوب بدمج الكلمات والعبارات بطرق جديدة، مما يتيح التعبير عن مفاهيم جديدة باستمرار.

في مرحلة ما، كانت الواجهات القائمة على اللغة، مثل أوامر BASIC وDOS في الثمانينيات والتسعينيات، هي الطريقة الرئيسية للتفاعل مع الحواسيب. أما في الاستخدام الروتيني، فقد استُبدلت إلى حد كبير بواجهات مرئية أسهل تعلماً لكنها أقل حرية. لكن إن عرفت أين تنظر، فاللغات ما تزال موجودة. إحداها، JavaScript، مدمجة في كل متصفح ويب حديث — وبالتالي متاحة على كل جهاز تقريباً.

سيحاول هذا الكتاب تعريفك بهذه اللغة بما يكفي لفعل أشياء مفيدة ومسلية بها.

عن البرمجة

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

ستكون هناك أوقات يبدو فيها قراءة هذا الكتاب محبطة للغاية. إذا كنت جديداً على البرمجة، فسيكون هناك الكثير من المادة الجديدة التي تُهضم. وكثير من هذه المادة سيُدمج بعد ذلك بطرق تتطلب منك إجراء روابط إضافية.

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

عندما يصبح الفعل غير مجدٍ، اجمع المعلومات؛ وعندما تصبح المعلومات غير مجدية، نم.

— أورسولا ك. لو غوين، اليد اليسرى للظلام

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

الحاسوب آلة مادية تستضيف هذه الآلات غير المادية. والحواسيب نفسها لا تستطيع إلا فعل أشياء بليدة ومباشرة. وسبب فائدتها الكبيرة أنها تفعل هذه الأشياء بسرعة هائلة لا تُصدق. ويمكن للبرنامج أن يجمع ببراعة عدداً هائلاً من هذه الأفعال البسيطة لفعل أشياء معقدة جداً.

البرنامج بناء من الفكر. تكلفة بنائه صفر، ووزنه صفر، وينمو بسهولة تحت أصابعنا أثناء الكتابة. لكن كلما نما البرنامج، نما تعقيده. ومهارة البرمجة هي مهارة بناء برامج لا تُربك المبرمج. وأفضل البرامج هي التي تنجح في فعل شيء ممتع مع بقائها سهلة الفهم.

يعتقد بعض المبرمجين أن أفضل إدارة لهذا التعقيد تكون باستخدام مجموعة صغيرة فقط من التقنيات المفهومة جيداً في برامجهم. لقد وضعوا قواعد صارمة («أفضل الممارسات») تحدد الشكل الذي ينبغي أن تكون عليه البرامج، ويلتزمون بعناية بمنطقتهم الآمنة الصغيرة.

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

لماذا تهم اللغة

في البداية، عند ولادة الحوسبة، لم تكن هناك لغات برمجة. كانت البرامج تبدو شيئاً كهذا:

00110001 00000000 00000000
00110001 00000001 00000001
00110011 00000001 00000010
01010001 00001011 00000010
00100010 00000010 00001000
01000011 00000001 00000000
01000001 00000001 00000001
00010000 00000010 00000000
01100010 00000000 00000000

هذا برنامج لجمع الأعداد من 1 إلى 10 معاً وطباعة النتيجة: 1 + 2 + ... + 10 = 55. كان يمكن تشغيله على آلة افتراضية بسيطة. ولبرمجة الحواسيب المبكرة، كان لا بد من ضبط مصفوفات كبيرة من المفاتيح في الموضع الصحيح أو خرم ثقوب في شرائط من الكرتون وإدخالها إلى الحاسوب. يمكنك تخيل مدى الممل وسهولة الخطأ في هذه العملية. حتى كتابة برامج بسيطة تطلبت كثيراً من الذكاء والانضباط. أما المعقدة فكانت شبه مستحيلة التصور.

بالطبع، إدخال هذه الأنماط الغامضة من البتات (الواحدات والأصفار) يدوياً منح المبرمج إحساساً عميقاً بأنه ساحر عظيم. ولا بد أن لذلك قيمة ما في الرضا الوظيفي.

كل سطر في البرنامج السابق يحتوي تعليمة واحدة. ويمكن كتابته بالإنجليزية هكذا:

  1. خزّن العدد 0 في موقع الذاكرة 0.
  2. خزّن العدد 1 في موقع الذاكرة 1.
  3. خزّن قيمة موقع الذاكرة 1 في موقع الذاكرة 2.
  4. اطرح العدد 11 من القيمة الموجودة في موقع الذاكرة 2.
  5. إذا كانت القيمة في موقع الذاكرة 2 هي العدد 0، فتابع بالتعليمة 9.
  6. أضف قيمة موقع الذاكرة 1 إلى موقع الذاكرة 0.
  7. أضف العدد 1 إلى قيمة موقع الذاكرة 1.
  8. تابع بالتعليمة 3.
  9. أخرج قيمة موقع الذاكرة 0.

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

  Set “total” to 0.
  Set “count” to 1.
[loop]
  Set “compare” to “count”.
  Subtract 11 from “compare”.
  If “compare” is 0, continue at [end].
  Add “count” to “total”.
  Add 1 to “count”.
  Continue at [loop].
[end]
  Output “total”.

هل تستطيع أن ترى كيف يعمل البرنامج في هذه المرحلة؟ السطران الأولان يمنحان موقعَي ذاكرة قيمتيهما الابتدائية: سيُستخدم total لبناء نتيجة الحساب، وسيتابع count العدد الذي ننظر إليه حالياً. والأسطر التي تستخدم compare هي على الأرجح الأكثر إرباكاً. يريد البرنامج أن يرى ما إذا كان count يساوي 11 ليقرر ما إذا كان يمكنه التوقف عن العمل. ولأن آلتنا الافتراضية بدائية نوعاً ما، فإنها تستطيع فقط اختبار ما إذا كان العدد صفراً واتخاذ قرار بناءً على ذلك. لذلك تستخدم موقع الذاكرة المسمّى compare لحساب قيمة count - 11 وتتخذ قراراً بناءً على تلك القيمة. والسطران التاليان يضيفان قيمة count إلى النتيجة ويزيدان count بمقدار 1 في كل مرة يقرر البرنامج أن count ليس 11 بعد.

إليك البرنامج نفسه بلغة JavaScript:

let total = 0, count = 1;
while (count <= 10) {
  total += count;
  count += 1;
}
console.log(total);
// → 55

يمنحنا هذا الإصدار بضع تحسينات إضافية. والأهم أنه لم تعد هناك حاجة لتحديد الطريقة التي نريد أن يقفز بها البرنامج ذهاباً وإياباً — فبنية while تتولى ذلك. وهي تستمر في تنفيذ الكتلة (المحاطة بأقواس) أسفلها ما دام الشرط المعطى لها يتحقق. وذلك الشرط هو count <= 10، أي «العدّاد أصغر من أو يساوي 10». لم نعد مضطرين لإنشاء قيمة مؤقتة ومقارنتها بالصفر، فذلك مجرد تفصيل غير مثير. وجزء من قوة لغات البرمجة أنها تتولى عنا التفاصيل غير المثيرة.

في نهاية البرنامج، بعد انتهاء بنية while، تُستخدم عملية console.log لكتابة النتيجة.

وأخيراً، إليك كيف قد يبدو البرنامج لو تُصادف أن لدينا العمليتين المريحتين range وsum، اللتين تنشئان على التوالي مجموعة من الأعداد ضمن نطاق وتحسبان مجموع مجموعة من الأعداد:

console.log(sum(range(1, 10)));
// → 55

مغزى هذه القصة أن البرنامج نفسه يمكن التعبير عنه بطرق طويلة وقصيرة، وغير مقروءة ومقروءة. الإصدار الأول من البرنامج كان غامضاً للغاية، بينما هذا الأخير شبه إنجليزي: log (سجّل) الـ sum (مجموع) الـ range (نطاق) الأعداد من 1 إلى 10. (سنرى في فصول لاحقة كيف نعرّف عمليات مثل sum وrange.)

لغة البرمجة الجيدة تساعد المبرمج بالسماح له بالحديث عن الأفعال التي على الحاسوب تنفيذها على مستوى أعلى. فهي تساعد في حذف التفاصيل، وتقدم وحدات بناء مريحة (مثل while وconsole.log)، وتتيح لك تعريف وحدات بنائك الخاصة (مثل sum وrange)، وتجعل تلك الوحدات سهلة التركيب.

ما هي JavaScript؟

قُدّمت JavaScript في عام 1995 كطريقة لإضافة برامج إلى صفحات الويب في متصفح Netscape Navigator. ومنذ ذلك الحين تبنتها جميع متصفحات الويب الرسومية الرئيسية الأخرى. لقد جعلت تطبيقات الويب الحديثة ممكنة — أي التطبيقات التي يمكنك التفاعل معها مباشرة دون إعادة تحميل الصفحة مع كل إجراء. وتُستخدم JavaScript أيضاً في المواقع التقليدية أكثر لتقديم أشكال متنوعة من التفاعل والذكاء.

من المهم ملاحظة أن JavaScript لا علاقة لها تقريباً بلغة البرمجة المسماة Java. فالاسم المشابه استُوحي من اعتبارات تسويقية لا من حكم سليم. فعندما كانت JavaScript تُقدَّم، كانت لغة Java تُسوَّق بقوة وتكتسب شعبية. ورأى أحدهم أنها فكرة جيدة أن يستغل هذا النجاح. والآن علينا أن نتحمل هذا الاسم.

بعد تبنيها خارج Netscape، كُتبت وثيقة معيارية لوصف الطريقة التي ينبغي أن تعمل بها لغة JavaScript حتى تتأكد مختلف البرمجيات التي ادعت دعم JavaScript أنها تقدم فعلاً اللغة نفسها. ويُسمى هذا معيار ECMAScript، نسبة إلى منظمة Ecma International التي أجرت التوحيد القياسي. وعملياً، يمكن استخدام المصطلحين ECMAScript وJavaScript بالتبادل — فهما اسمان للغة نفسها.

هناك من سيقول أشياء فظيعة عن JavaScript. وكثير من هذه الأشياء صحيح. عندما طُلب مني كتابة شيء بلغة JavaScript لأول مرة، سرعان ما صرت أحتقرها. كانت تقبل تقريباً أياً كان ما أكتبه لكنها تفسره بطريقة مختلفة تماماً عما قصدت. وكان لذلك علاقة كبيرة بأنني لم أكن أدري ما أفعله، بالطبع، لكن هناك مشكلة حقيقية هنا: JavaScript متسامحة بشكل سخيف في ما تسمح به. والفكرة خلف هذا التصميم كانت أن تجعل البرمجة بلغة JavaScript أسهل للمبتدئين. لكنها في الواقع تجعل العثور على المشكلات في برامجك أصعب في الغالب لأن النظام لن ينبهك إليها.

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

هناك عدة إصدارات من JavaScript. كان الإصدار 3 من ECMAScript هو الإصدار المدعوم على نطاق واسع خلال صعود JavaScript إلى الهيمنة، تقريباً بين عامي 2000 و2010. وخلال هذه الفترة كان العمل جارياً على إصدار طموح رقم 4 خطط لعدد من التحسينات والتوسعات الجذرية للغة. لكن تغيير لغة حية ومستخدمة على نطاق واسع بهذه الطريقة الجذرية اتضح أنه صعب سياسياً، وتُخلي عن العمل على الإصدار 4 في عام 2008. وصدر إصدار أقل طموحاً بكثير هو الإصدار 5، الذي أجرى بعض التحسينات غير المثيرة للجدل فقط، في عام 2009. وفي 2015 صدر الإصدار 6، وهو تحديث رئيسي ضم بعض الأفكار المخطط لها في الإصدار 4. ومنذ ذلك الحين صارت تصدر تحديثات جديدة صغيرة كل عام.

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

ليست متصفحات الويب المنصات الوحيدة التي تُستخدم فيها JavaScript. فبعض قواعد البيانات، مثل MongoDB وCouchDB، تستخدم JavaScript كلغة نصوص برمجية واستعلام. وعدد من المنصات لبرمجة سطح المكتب والخوادم، وأبرزها مشروع Node.js (موضوع الفصل 20)، يوفر بيئة لبرمجة JavaScript خارج المتصفح.

الشيفرة، وما الذي نفعله بها

الشيفرة هي النص الذي تتكون منه البرامج. ومعظم فصول هذا الكتاب تحتوي قدراً كبيراً من الشيفرة. أعتقد أن قراءة الشيفرة وكتابتها جزءان لا غنى عنهما في تعلم البرمجة. حاول ألا تمر على الأمثلة مرور الكرام — اقرأها بانتباه وافهمها. قد يكون هذا بطيئاً ومربكاً في البداية، لكنني أعدك بأنك ستتقنها بسرعة. والأمر نفسه ينطبق على التمارين. لا تفترض أنك فهمتها حتى تكتب حلاً عاملاً فعلاً.

أنصحك بتجربة حلولك للتمارين في مفسّر JavaScript فعلي. بهذه الطريقة ستحصل على تغذية راجعة فورية عما إذا كان ما تفعله يعمل، وآمل أن تميل إلى التجربة وتجاوز التمارين.

عند قراءة هذا الكتاب في متصفحك، يمكنك تحرير (وتشغيل) جميع برامج الأمثلة بالنقر عليها.

وتشغيل البرامج المعرَّفة في هذا الكتاب خارج موقع الكتاب يتطلب بعض الحذر. فأمثلة كثيرة قائمة بذاتها ويجب أن تعمل في أي بيئة JavaScript. لكن الشيفرة في الفصول اللاحقة كثيراً ما تُكتب لبيئة محددة (المتصفح أو Node.js) ولا تعمل إلا فيها. إضافة إلى ذلك، تعرّف فصول كثيرة برامج أكبر، وتعتمد القطع البرمجية الواردة فيها على بعضها بعضاً أو على ملفات خارجية. وتوفر بيئة التجربة على الموقع روابط لملفات ZIP تحتوي جميع النصوص البرمجية وملفات البيانات اللازمة لتشغيل شيفرة فصل معين.

نظرة عامة على هذا الكتاب

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

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

وبعد فصل مشروع أول يبني روبوت توصيل بدائياً، يستمر الجزء اللغوي من الكتاب بفصول عن معالجة الأخطاء وإصلاح العلل، والتعابير النمطية (أداة مهمة للعمل مع النصوص)، والوحدات (دفاع آخر ضد التعقيد)، والبرمجة غير المتزامنة (التعامل مع الأحداث التي تستغرق وقتاً). ويُختتم الجزء الأول من الكتاب بـفصل المشروع الثاني حيث ننفّذ لغة برمجة.

ويصف الجزء الثاني من الكتاب، من الفصل 13 إلى الفصل 19، الأدوات المتاحة لـ JavaScript في المتصفح. وستتعلم عرض الأشياء على الشاشة (الفصلان 14 و17)، والاستجابة لمدخلات المستخدم (الفصل 15)، والتواصل عبر الشبكة (الفصل 18). وهناك أيضاً فصلان مشروعان في هذا الجزء: بناء لعبة منصات وبرنامج رسم بالبكسلات.

ويصف الفصل 20 بيئة Node.js، ويبني الفصل 21 موقعاً صغيراً باستخدام تلك الأداة.

اصطلاحات الطباعة

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

function factorial(n) {
  if (n == 0) {
    return 1;
  } else {
    return factorial(n - 1) * n;
  }
}

أحياناً، لإظهار المخرجات التي ينتجها برنامج ما، تُكتب المخرجات المتوقعة بعده، مسبوقة بشرطتين مائلتين وسهم.

console.log(factorial(8));
// → 40320

حظاً موفقاً!