الوحدة 2 · المنطق والدوال
الدوال: التصريح والدوال السهمية والقيم الافتراضية
19 دقراءة 4 دبيئة تجريب الكود
الدرس في لمحة
تكتب دوالّك الخاصة بأسلوب التصريح وبأسلوب الدوال السهمية، وتمرّر الوسائط إليها وتستخرج النتائج منها بـ return، وتمنح المعاملات قيمًا افتراضية، وتمرّر الدوال إلى دوال أخرى.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
في الدرسين السابقين أكملت أجسام دوال كُتبت لك. والآن تكتب دوالّك بنفسك. الدالة (function) قطعة من البرنامج لها اسم ويمكن إعادة استخدامها: تكتب الخطوات مرة واحدة وتنفّذها متى احتجت، بمدخلات مختلفة. يُنسّق Pocket المبالغ المالية في أماكن كثيرة؛ ودون الدوال ستنسخ (cents / 100).toFixed(2) في كل منها، ثم تُصلح كل نسخة حين يتغيّر التنسيق.
التصريح بدالة واستدعاؤها
function formatMoney(cents) {
const dollars = (cents / 100).toFixed(2);
return `${dollars}`;
}
console.log(formatMoney(1220));
console.log(formatMoney(450));الأسطر الخمسة الأولى تصريح دالة (function declaration). إنها لا تنفّذ شيئًا؛ بل تُنشئ دالة اسمها formatMoney وتحفظ خطواتها. وcents معامل (parameter)، أي اسم لمُدخل ليست له قيمة بعد.
أما formatMoney(1220) فهو استدعاء (call). والقيمة بين القوسين، 1220، وسيط (argument). حين يصل المحرّك إلى الاستدعاء، يوقف السطر الحالي مؤقتًا، ويقفز إلى داخل الدالة وcents تشير إلى 1220، فينفّذ الجسم، ثم يعود حين يصل إلى return. بعدها يُستبدل تعبير الاستدعاء بالقيمة المُعادة، "$12.20"، فتطبعها console.log.
يمكن أن يكون للدالة عدّة معاملات تفصل بينها فواصل، وتُطابَق الوسائط معها حسب الموضع: الوسيط الأول يذهب إلى المعامل الأول، وهكذا.
لـ return وظيفتان: تحدّد النتيجة، وتُنهي الدالة في مكانها. أي سطر بعد return في الكتلة نفسها لا يُنفَّذ أبدًا. وإذا انتهت الدالة دون أن تصل إلى return، فإن قيمة الاستدعاء تكون undefined.
المعاملات الافتراضية
إذا استدعيت دالة بوسائط أقل من معاملاتها، تكون المعاملات الناقصة undefined. والمعامل الافتراضي (default parameter) يمنحها قيمة معقولة بدلًا من ذلك:
function formatMoney(cents, symbol = "$") {
return `${symbol}${(cents / 100).toFixed(2)}`;
}
console.log(formatMoney(1220));
console.log(formatMoney(1220, "€"));تُستخدم القيمة الافتراضية حين يكون الوسيط مفقودًا أو undefined، وحينها فقط. أما تمرير 0 أو "" أو null فيُعدّ وسيطًا حقيقيًا.
الدوال السهمية
هناك طريقة ثانية أقصر لكتابة الدوال، هي الدالة السهمية (arrow function). إنها قيمة، لذلك تخزّنها في const:
const toCents = (dollars) => Math.round(dollars * 100);
const isBig = (cents) => cents >= 10000;
console.log(toCents(12.2), isBig(toCents(120)));حين يكون الجسم تعبيرًا واحدًا، كما هنا، تحذف الأقواس المعقوفة وreturn: فقيمة التعبير تُعاد تلقائيًا. وحين تحتاج إلى عدّة تعليمات، استخدم الأقواس المعقوفة، وعندها تصبح return مطلوبة من جديد:
const budgetLeft = (budget, spent) => {
const left = budget - spent;
return left > 0 ? left : 0;
};
console.log(budgetLeft(2000, 2200));أيّ الأسلوبين تستخدم؟ كلاهما منتشر في الكود الحقيقي. والاختيار الافتراضي الشائع، الذي تتبعه هذه الدورة: التصريح للدوال المسمّاة في المستوى الأعلى، والدوال السهمية للدوال القصيرة التي تُمرَّر إلى دوال أخرى. وهناك فرق عملي واحد: تصريحات الدوال تُرفع (hoisting)، أي يمكنك استدعاؤها في سطر يسبق مكان كتابتها. أما الدالة السهمية المخزّنة في const فلا توجد إلا بعد أن يُنفَّذ سطرها.
الدوال قيم
الدالة في JavaScript قيمة مثل الرقم أو النص. يمكنك تخزينها، ويمكنك تمريرها إلى دالة أخرى بصفتها وسيطًا. وهذه الفكرة وراء جزء كبير من JavaScript الحديثة:
function applyToAll(amounts, transform) {
const results = [];
for (const amount of amounts) {
results.push(transform(amount));
}
return results;
}
const formatMoney = (cents) => `${(cents / 100).toFixed(2)}`;
console.log(applyToAll([450, 1220], formatMoney));
console.log(applyToAll([450, 1220], (c) => c * 2));applyToAll لا تعرف ما تفعله transform ولا يهمّها ذلك؛ إنها تستدعيها مرة لكل عنصر وتجمع النتائج باستخدام push، التي تضيف عنصرًا إلى نهاية المصفوفة. والدالة التي تُمرَّر بهذه الطريقة تُسمّى callback (دالة استدعاء راجع). لاحظ أنك تمرّر formatMoney دون أقواس: فأنت تسلّم الدالة نفسها، لا تستدعيها. وللمصفوفات أداة مدمجة تفعل هذا بالضبط، اسمها map، وسيضعها القسم 3 موضع العمل.
دوال صغيرة ونقية
لاحظ ما تشترك فيه كل الدوال المساعدة في هذا الدرس: إنها لا تستخدم إلا معاملاتها، وتُرجع نتيجة، ولا تغيّر شيئًا خارجها. الدالة من هذا النوع تُسمّى نقية (pure). أعطها الوسائط نفسها تُعِد الإجابة نفسها في كل مرة، فتستطيع اختبارها بسطر واحد، وإعادة استخدامها في أي مكان، والثقة بها دون أن تقرأ جسمها مجددًا.
ليست كل دالة قادرة على أن تكون نقية. لا بدّ لشيء ما في النهاية أن يطبع على الشاشة أو يحفظ البيانات. والعادة التي تُبقي البرامج تحت السيطرة هي أن تُجري الحسابات في دوال صغيرة نقية، وأن تُبقي الطباعة والحفظ في أماكن قليلة ذات أسماء واضحة. ويتبع Pocket هذا الفصل حتى التطبيق النهائي.
الدوال تُنشئ داخلها عالمًا صغيرًا من الأسماء خاصًا بها. وعلاقة هذا العالم بالكود المحيط به تُسمّى النطاق (scope)، وهي موضوع الدرس التالي.
أهم النقاط
- الدالة تحزم خطوات تحت اسم واحد؛ والمعاملات (parameters) هي المدخلات التي تعلنها الدالة، أما الوسائط (arguments) فهي القيم التي تمرّرها حين تستدعيها.
returnتُنهي الدالة وتُعيد قيمة؛ والدالة التي لا تحتوي علىreturnتُعيدundefined.- الدوال السهمية (
(x) => x * 2) صياغة أقصر؛ ومع الأقواس المعقوفة تحتاج إلىreturnصريحة. - المعاملات الافتراضية (
symbol = "quot;) تُطبَّق حين يكون الوسيط مفقودًا أوundefined. - الدوال قيم، لذلك يمكنك تخزينها في متغيّرات وتمريرها إلى دوال أخرى.