EduFlow
أساسيات JavaScript
⁦0%⁩

الوحدة 2 · المنطق والدوال

الدوال: التصريح والدوال السهمية والقيم الافتراضية

19 دقراءة 4 دبيئة تجريب الكود

الدرس في لمحة

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

  1. 1التصريح بدالة واستدعاؤها
  2. 2المعاملات الافتراضية
  3. 3الدوال السهمية
  4. 4الدوال قيم
  5. 5دوال صغيرة ونقية

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

في الدرسين السابقين أكملت أجسام دوال كُتبت لك. والآن تكتب دوالّك بنفسك. الدالة (function) قطعة من البرنامج لها اسم ويمكن إعادة استخدامها: تكتب الخطوات مرة واحدة وتنفّذها متى احتجت، بمدخلات مختلفة. يُنسّق Pocket المبالغ المالية في أماكن كثيرة؛ ودون الدوال ستنسخ (cents / 100).toFixed(2) في كل منها، ثم تُصلح كل نسخة حين يتغيّر التنسيق.

التصريح بدالة واستدعاؤها

JavaScript
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.

الاستدعاء formatMoney(1220) يمرّر 1220 إلى المعامل cents. يُنفَّذ جسم الدالة ويُعيد النص $12.20، الذي يحلّ محلّ الاستدعاء في السطر الأصلي. formatMoney(1220) function formatMoney cents = 1220 dollars = "12.20" return "$12.20" الوسيط القيمة المُعادة
الاستدعاء يُرسل الوسائط إلى الداخل ويستعيد القيمة المُعادة

يمكن أن يكون للدالة عدّة معاملات تفصل بينها فواصل، وتُطابَق الوسائط معها حسب الموضع: الوسيط الأول يذهب إلى المعامل الأول، وهكذا.

لـ return وظيفتان: تحدّد النتيجة، وتُنهي الدالة في مكانها. أي سطر بعد return في الكتلة نفسها لا يُنفَّذ أبدًا. وإذا انتهت الدالة دون أن تصل إلى return، فإن قيمة الاستدعاء تكون undefined.

المعاملات الافتراضية

إذا استدعيت دالة بوسائط أقل من معاملاتها، تكون المعاملات الناقصة undefined. والمعامل الافتراضي (default parameter) يمنحها قيمة معقولة بدلًا من ذلك:

JavaScript
function formatMoney(cents, symbol = "$") {
  return `${symbol}${(cents / 100).toFixed(2)}`;
}

console.log(formatMoney(1220));
console.log(formatMoney(1220, "€"));

تُستخدم القيمة الافتراضية حين يكون الوسيط مفقودًا أو undefined، وحينها فقط. أما تمرير 0 أو "" أو null فيُعدّ وسيطًا حقيقيًا.

الدوال السهمية

هناك طريقة ثانية أقصر لكتابة الدوال، هي الدالة السهمية (arrow function). إنها قيمة، لذلك تخزّنها في const:

JavaScript
const toCents = (dollars) => Math.round(dollars * 100);
const isBig = (cents) => cents >= 10000;

console.log(toCents(12.2), isBig(toCents(120)));

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

JavaScript
const budgetLeft = (budget, spent) => {
  const left = budget - spent;
  return left > 0 ? left : 0;
};
console.log(budgetLeft(2000, 2200));

أيّ الأسلوبين تستخدم؟ كلاهما منتشر في الكود الحقيقي. والاختيار الافتراضي الشائع، الذي تتبعه هذه الدورة: التصريح للدوال المسمّاة في المستوى الأعلى، والدوال السهمية للدوال القصيرة التي تُمرَّر إلى دوال أخرى. وهناك فرق عملي واحد: تصريحات الدوال تُرفع (hoisting)، أي يمكنك استدعاؤها في سطر يسبق مكان كتابتها. أما الدالة السهمية المخزّنة في const فلا توجد إلا بعد أن يُنفَّذ سطرها.

الدوال قيم

الدالة في JavaScript قيمة مثل الرقم أو النص. يمكنك تخزينها، ويمكنك تمريرها إلى دالة أخرى بصفتها وسيطًا. وهذه الفكرة وراء جزء كبير من 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.
  • الدوال قيم، لذلك يمكنك تخزينها في متغيّرات وتمريرها إلى دوال أخرى.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

ماذا يطبع هذا الكود؟

JavaScript
const double = (n) => {
  n * 2;
};
console.log(double(4));
السؤال 2 من 4

الدالة function formatMoney(cents, symbol = "

quot;) { … } استُدعيت هكذا: formatMoney(450, undefined). ما قيمة symbol داخلها؟

السؤال 3 من 4

أيّ سطر يستدعي isBig قبل تعريفها دون أن يحدث خطأ؟

السؤال 4 من 4

لديك const amounts = [450, 1220]; وfunction toDollars(c) { return c / 100; }. ماذا يحتاج منك amounts.map(toDollars)؟

تدريب

بيئة تجريب الكود

الدوال المساعدة للمال في Pocket

اكتب أربع دوال صغيرة سيستخدمها Pocket من الآن فصاعدًا:

  1. toCents(dollars) تُرجع المبلغ بالسنتات الصحيحة (4.1 تعطي 410).
  2. formatMoney(cents, symbol) تُرجع نصًا مثل "$12.20". والقيمة الافتراضية لـ symbol هي "
    quot;
    .
  3. isBig، وهي دالة سهمية تُرجع true لمبلغ 10000 سنت أو أكثر.
  4. countWhere(amounts, test) تُرجع عدد العناصر في amounts التي تجعل الـ callback test(amount) تُرجع قيمة truthy.
// 1. Dollars (like 4.1) to whole cents (410)
function toCents(dollars) {
}

// 2. Cents to a display string, with a symbol that defaults to "
quot; function formatMoney(cents) { } // 3. Replace null with an arrow function: true for 10000 cents or more const isBig = null; // 4. Count the amounts for which test(amount) returns true function countWhere(amounts, test) { return 0; } console.log(formatMoney(toCents(12.2)));
جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

الـ console

(لا مخرجات)

الفحوص

  • toCents تُرجع سنتات صحيحة
  • formatMoney تُرجع نصوصًا مثل “$12.20”
  • formatMoney تستخدم رمزًا مخصّصًا، وقيمته الافتراضية “$”
  • isBig دالة سهمية بحدّ 10000 سنت
  • countWhere تعدّ العناصر التي تجتاز الـ callback