الاستدعاء الذاتي (Recursion): لما الدالة تحلّ المشكلة بإنها تنادي نفسها
المستوى: مبتدئ. المقال ده مناسب لو انت لسه في بداية طريقك في البرمجة، سمعت كلمة Recursion كذا مرة، وكل ما تحاول تفهمها دماغك بتلفّ في حلقة. مش هتحتاج غير إنك تعرف تكتب دالة بسيطة وتنادي عليها.
بعد المقال ده هتقدر تقرا أي دالة recursive وتعرف بالظبط بتعمل إيه، وهتعرف تكتب واحدة بنفسك من غير ما تقع في الحلقة اللا نهائية اللي بتوقّع البرنامج. الاستدعاء الذاتي مش حيلة ذكية للاستعراض — هو أوضح طريقة لحل نوع معيّن من المشاكل، وكارثة لو استخدمته في النوع الغلط.
الفكرة الأول في مثال — قبل أي تعريف
تخيّل إنك واقف في طابور طويل، وعايز تعرف انت رقم كام، بس مش شايف أوله. أبسط حل: تسأل اللي قدامك "انت رقم كام؟". هو برضه مش عارف، فيسأل اللي قدامه نفس السؤال، وهكذا.
السؤال بيتنقل لقدّام لحد ما يوصل لأول واحد في الطابور. ده الوحيد اللي بيرد على طول من غير ما يسأل حد: "أنا رقم 1". الرد ده بيرجع للي وراه، يزوّد عليه واحد ويبقى 2، يرجّعه للي وراه يبقى 3، لحد ما الرقم يوصلك انت.
اللي حصل ده بالظبط هو الـ Recursion: كل واحد حلّ نسخة أصغر من نفس المشكلة، واعتمد على إن في "حالة بسيطة" في الآخر بترد من غير ما تسأل تاني. ركّز في حاجتين: في خطوة بتصغّر المشكلة (تسأل اللي قدامك)، وفي نقطة توقف (أول واحد في الطابور). الاتنين دول هما كل الحكاية.
تعريف الـ Recursion بشكل دقيق
الـ Recursion (الاستدعاء الذاتي) هو أسلوب الدالة فيه بتستدعي نفسها لحل نسخة أصغر من نفس المشكلة، لحد ما توصل لحالة بسيطة جدًا تقدر تحلها فورًا من غير استدعاء جديد.
الحالة البسيطة دي اسمها base case (حالة التوقف)، والجزء اللي بيستدعي نفسه على نسخة أصغر اسمه recursive case (الحالة التكرارية). أي دالة recursive من غير base case واضح هتفضل تنادي نفسها للأبد، لحد ما الذاكرة تخلص ويقع البرنامج.
أي دالة recursive لازم فيها حاجتين
خد المثال الكلاسيكي: مضروب العدد (factorial). مضروب 5 يعني 5 × 4 × 3 × 2 × 1. لاحظ إن مضروب 5 = 5 × مضروب 4. ده تعريف recursive جاهز.
function factorial(n) {
if (n <= 1) return 1; // base case: نقطة التوقف
return n * factorial(n - 1); // recursive case: نسخة أصغر
}
console.log(factorial(5)); // 120
السطر الأول هو حالة التوقف: لو n وصلت 1، رجّع 1 على طول وبلاش استدعاء جديد. السطر التاني بيصغّر المشكلة بـ factorial(n - 1). الترتيب مهم — لو نسيت الـ base case، الدالة مش هتعرف تقف خالص.
إيه اللي بيحصل في الذاكرة فعليًا: الـ Call Stack
تخيّل رصّة أطباق. كل ما تحتاج طبق جديد، بتحطّه فوق الرصّة. وأول ما تخلّص، بتشيل الطبق اللي فوق خالص الأول، مش اللي تحت. مينفعش توصل للي تحت قبل ما تشيل اللي فوقه.