الدوال (متوسط)

مقدمة

تحدثنا عن أساسيات الدوال في درس الدوال في المستوى اﻹبتدائي، واﻵن سنتعمق أكثر في الدوال وتفاصيلها وأنواعها

إذا كنت لم تقرأ درس الدوال في المستوى الإبتدائي، يجب عليك قراءته من هنا وفهمه جيداً قبل استكمال الدرس

المدخلات تقبل التعبيرات

يمكن أن يكون المدخل للدالة عبارة عن تعبير، مثلاً لدينا دالة function test(num) بدلاً من إدخال المدخل مباشرة test(5) يمكننا إدخال أي تعبير، test(5+5) سيقوم المفسر بمعالجة التعبير أولاً والحصول على ناتجه، ثم يستبدل التعبير بالناتج، فسيعتبرها test(10)

function printExp(num){
  console.log(num);
}
printExp(5);
printExp(5+5);
printExp(10 > 5);

var name = "Ebrahim";
printExp(name);
printExp("Hello: " + name);
ناتج التشغيل 5
10
true
Ebrahim
Hello: Ebrahim

إرجاع نواتج من الدالة

في بعض الدوال نحتاج لإرجاع ناتج لنستخدمه في باقي البرنامج، فكر في المشكلة التالية:

مشكلة التحقق من نوع الحساب

نريد إنشاء دالة لنستخدمها مرات متعددة في البرنامج، تأخذ الدالة قاموس (dictionary) فيه بيانات الحساب، تقوم الدالة بالتحقق من أن الحساب هو حساب طالب، وتقوم بإرجاع الناتج true إن كان حساب طالب، و false إن كان حساب معلم، فمهمة الدالة هي التحقق فقط من الحساب، لا تقوم بأي إجراء، ﻷننا نريد استخدامها مثلاً مرة في كتابة "طالب" تحت اسم الطالب، و"معلم" تحت اسم المعلم، ونريد استخدامها مرة أخرى في إظهار صفحات مخصصة للمعلم فقط، وصفحات مخصصة للطالب فقط... لذلك الدالة هنا لا تقوم بأي إجراء، هي فقط تتحقق وتقوم بإرجاع الناتج، ويقوم باقي الكود باستقبال هذا الناتج لاستخدامه في تنفيذ اﻹجراء، مثلاً كتابة "طالب" وهكذا، في هذه الحالة نحتاج لاستخدام اﻷمر return

اﻷمر return

return هي كلمة إنجليزية تعني "إرجاع" ومهمتها إرجاع قيمة من الدالة

مثال لدالة تتحقق من النجاح، تأخذ عدد كمُدخل وهو عبارة عن درجة الطالب، وتتحقق منها فإن كانت أكبر من 50 تقوم بإرجاع true أي أن الطالب نجح، غير ذلك تقوم بإرجاع false ﻷن الدرجة أقل من 50.

function succeeded(degree){
  if (degree > 50){
    return true;
  }else{
    return false;
  }
}

اﻷمر return يأتي بعده تعبيراً، يمكن أن يكون متغير، ويمكن أن يكون أي نوع من أنواع البيانات، (عدد، نص، مصفوفة، قاموس، منطقية) ويمكن أن يكون أي تعبير من التعبيرات، مثلاً تعبير حسابي return 5+10، أو تعبير مقارنة: return 5 > 3 سيقوم بإرجاع true

ويمكننا استدعاء الدالة واستخدام البيانات الراجعة منها كقيمة لمتغير:

function succeeded(degree){
  if (degree > 50){
    return true;
  }else{
    return false;
  }
}

var success = succeeded(70);
if (success){
  console.log("ناجح");
}else{
  console.log("راسب");
}
ناتج التشغيل ناجح

استدعاء الدالة يعتبر تعبيراً: عندما يمر المفسر على استدعاء دالة تقوم بإرجاع قيمة، فإنه يقوم بتنفيذها أولاً ثم يستبدلها بالقيمة التي ترجع منها، فمثلاً var success = succeeded(40) الناتج سيكون false إذن سيقوم المفسر بإعتبارها: var success = false، ونعنى أن استدعاء الدالة مثله مثل التعبيرات الحسابية أو أي تعبير آخر، ارجع لدرس التعبيرات، ونستنتج من هذا أننا يمكننا استدعاء الدالة في أي مكان يتعامل مع التعبيرات، مثلاً في الشروط نستخدم تعبيرات المقارنة if (10 > 5) إذن الشروط تأخذ تعبير، بالتالي يمكننا استخدام الدالة كتعبير if (succeeded(60)) وإذا كانت القيمة الراجعة من الدالة تساوي true سيتم تنفيذ كتلة أوامر الشرط، ويمكن أيضاً أن تكون الدالة مُدخل لدالة أخرى، ﻷن مدخلات الدالة تقبل تعبيرات، مثلاً: console.log( succeeded(40) ) سيكون الناتج false، سيقوم المفسر بمعالجة succeeded(40) أولاً ليأخذ الناتج الراجع من الدالة false ويعتبر أن اﻷمر هو console.log(false)

حل مشكلة التحقق من نوع الحساب

سنقوم بإنشاء دالة اسمها isStudent تقوم بإرجاع true إن كان نوع الحساب طالب، أما إن كان معلم تقوم بإرجاع false، وفي هذه الحالة سنفترض أن القاموس المُدخل للدالة يحتوي على بيانات الطالب، اسمه ونوع الحساب، {name: "Mohamed", type: "student"} أو type: "teacher" إن كان معلم:

function isStudent(account){
  if (account["type"] == "student"){
    return true;
  }else{
    return false;
  }
}

var student = {name: "Ebrahim", type: "student"};
var teacher = {name: "Mohamed", type: "teacher"};
if (isStudent(student)){
  console.log("طالب");
}else{
  console.log("معلم");
}
ناتج التشغيل طالب

جرب التحقق من متغير حساب المعلم، باستخدام isStudent(teacher) وانظر الناتج!

في المثال السابق استخدمنا الدالة في تعبير الشرط مع أمر if ﻷننا ذكرنا في ملاحظة قبل قليل أن استدعاء الدالة يعتبر تعبيراً.


تمرين اكتشف الخطأ

function getMonths(years){
  var months = years*12;
}

console.log(getMonths(2));
ناتج التشغيل undefined
اكتشف الخطأ

الكود السابق لا يعمل، من المفترض أن يقوم بطباعة 24 ﻷن الدالة تقوم بضرب عدد السنين في 12 لتحصل على عدد الشهور، لكن عند استدعاءها كمُدخل لدالة الطباعة تطبع undefined وتعني "غير معرف"

ما بعد return لا ينفذ

عندما يجد المفسّر اﻷمر return عند تنفيذ أوامر الدالة، يقوم بإرجاع القيمة ويتوقف عن تنفيذ باقي أوامر الدالة، ﻷن إرجاع القيمة من الدالة هو دائماً آخر شيء، ولذلك في المثال التالي لن يتنفذ أمر الطباعة الثاني:

function test(){
  console.log("test1");
  return false;
  console.log("test2");
}

test();
ناتج التشغيل test1

الدالة السابقة لن تقوم بتنفيذ السطر الثاني من أوامر الدالة، ﻷن الدالة قامت بإرجاع false بالتالي لن يتم طباعة "test2"

أنواع استخدامات الدوال

تنقسم أنواع الدوال من حيث اﻹستخدام إلى:

  • دوال معالجة البيانات: هو اﻹستخدام اﻷساسي للدوال، الدالة تأخذ مُدخلات وتقوم بمعالجتها ثم إرجاع نواتج.
  • دوال هيكلة البرنامج: هذا اﻹستخدام مخصص للدوال البرمجية فقط، ويمكن أن يكون بدون مُدخلات، وبدون نواتج، وتُستخدم للتنظيم وتقسيم البرنامج وتجنب تكرار اﻷكواد كما سنذكر لاحقاً في الدرس

دوال معالجة البيانات

الدالة تأخذ مُدخلات وتقوم بمعالجتها ثم إرجاع نواتج، ومن استخداماتها:

  • تعديل البيانات: مهمة الدالة أن تأخذ بيانات وتعدلها لتقوم بإرجاعها بشكل معين، مثلاً لدينا دالة تأخذ عدد كمُدخل، مثلاً 5 وتقوم بإرجاعه بشكل المبالغ المالية 5.00، ويمكن استخدام هذه الدالة في أي مكان في الموقع أو البرنامج نريد أن نُظهر فيه مبلغ، مثلاً سعر منتج.. وهكذا، وهناك مثال آخر متقدم وهو دالة تأخذ وقت بصيغة "4-2-2021 11:00:00" وتقوم بإرجاع الناتج وقت بصيغة "منذ 10 دقائق" أو "منذ يومين" حسب الوقت الحالي...
  • التحقق من البيانات: مثلاً إنشاء دالة تأخذ بيانات كمُدخلات، لتعالجها وتتحقق منها ثم تقوم بإرجاع قيمة منطقية (Boolean) true أو false ومن اﻷمثلة على هذا النوع: تخيل أن لدينا برنامج يقوم المستخدم بإدخال بريد إلكتروني، ونريد أن نسمح فقط بـ @gmail.com غير ذلك نطبع أن البريد اﻹلكتروني غير مسموح به، في هذه الحالة يمكننا إنشاء دالة تأخذ البريد اﻹلكتروني كمُدخل وتتحقق منه ثم تقوم بإرجاع true إن كان البريد اﻹلكتروني صحيح، وfalse إن كان البريد اﻹلكتروني غير مسموح به!

الدوال وهيكلة البرامج

استخدام الدوال في الهيكلة مختص بالبرمجة فقط، ويمكن أن تكون هذه الدوال بدون مُدخلات، وبدون نواتج ومن استخداماتها:

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

الهيكلة واﻷسلوب الذي نتبعه حتى اﻵن في البرمجة هو البرمجة اﻹجرائية (Procedural Programming) حيث يكون الكود عدة أوامر تحت بعض يمر عليها المفسر من اﻷعلى إلى اﻷسفل لتنفيذها كما هي بالترتيب، وهذا هو اﻷسلوب اﻷبسط ويمكن استخدامه فقط في البرامج البسيطة جداً والصغيرة، غير ذلك فتختلف هيكلة البرامج حسب حجمها، فالبرامج الكبيرة يمكن أن تتكون من عشرات اﻵلاف من اﻷسطر، فلا يمكن كتابتها في ملف واحد بأسلوب البرمجة اﻹجرائية ﻷن في هذه الحالة سيكون من شبه المستحيل تطوير البرنامج، وسيصعب جداً حل المشكلات وستظهر مشاكل لا حصر لها ولن يتمكن أي مبرمج أخر من التعديل على البرنامج، حتى مبرمج البرنامج اﻷساسي سيصعب عليه جداً التعديل على البرنامج، فإن حاول حل مشكلة ستظهر عشر مشكلات غيرها! لذلك يتم اﻹعتماد على اسلوب وهيكلة أفضل للبرامج المتوسطة وهي البرمجة الوظيفية (Functional Programming) وهي عبارة عن تقسيم البرنامج إلى عدة دوال كل منها ينفذ مهمة محددة، واستدعاء الدوال فقط في عدة أسطر أي يصبح البرنامج مكون من عدة أجزاء (دوال) كل منها منفصل عن اﻵخر وكل منها ينفذ شيء محدد، وبعد تجميعهم يُصبح البرنامج كاملاً ويسمى هذا اﻷسلوب البرمجي البرمجة الوظيفية (Functional Programming)

المساهمين

وجدت خطأ أو تريد المساهمة في محتوى الدرس؟ عدل الصفحة على Github