مستوى المقال: مبتدئ
لو شفت دالة JavaScript بتنده نفس اسمها جوّاها، ده مش غلط ولا bug. ده Recursion. في 7 دقايق هتفهم ليه الكود ده مش بيدخل في حلقة لا نهائية، وامتى تستخدمه بدل الـ for loop بالظبط.
المشكلة باختصار
أول مرة بتشوف دالة بتنده نفسها، الدماغ بترفض الفكرة. لأن لو الدالة بتنده نفسها، يبقى المفروض تفضل بتنده نفسها للأبد. الإجابة الصح: لأ، بشرط واحد بس. لو فهمت الشرط ده، Recursion هيبقى أبسط من الـ loops في حالات معينة — زي تصفّح مجلدات أو شجرة JSON أو DOM.
Recursion: لما الدالة تكون أبسط من الحلقة
مثال للمبتدئ — دمى ماتريوشكا
تخيّل عندك دمية ماتريوشكا روسية. بتفتحها، بتلاقي جوّاها دمية أصغر. بتفتح الصغيرة، بتلاقي جوّاها أصغر. بتفضل تفتح كل واحدة بنفس الخطوة بالظبط — لحد ما توصل لدمية صغيرة جدًا مش بتتفتح. هنا بتقف.
الـ recursion بنفس المنطق. الدالة بتعمل خطوة بسيطة على المدخل، وبعدين بتنده نفسها على نسخة أصغر من نفس المشكلة. بتفضل بتنده نفسها لحد ما توصل لحالة بسيطة جدًا الإجابة فيها معروفة على طول. الحالة دي اسمها base case. لو نسيت تكتبها، آه — هيدخل في حلقة لا نهائية فعلًا، والـ Node هيرميلك RangeError: Maximum call stack size exceeded بعد ثانية.
التعريف العلمي
Recursion هي تقنية تنفيذ بتنحلّ فيها مشكلة عبر استدعاء الدالة لنفسها على نسخة أصغر من نفس المشكلة. كل recursion صحيح بيلتزم بشرطين بدون استثناء:
- Base case: حالة بسيطة الدالة بترجع فيها قيمة فورًا بدون ما تنده نفسها.
- Recursive case: استدعاء للدالة على input أصغر بحيث إنه بيقترب من الـ base case في كل خطوة.
كل استدعاء للدالة بيتسجّل في حتة في الذاكرة اسمها call stack. كل إطار (frame) في الـ stack بيحتفظ بقيم المتغيرات بتاعت الاستدعاء ده لحد ما يخلّص. لما الـ base case يرد قيمة، الـ stack بيبدأ يفك من فوق لتحت، وكل استدعاء بياخد قيمة الاستدعاء اللي تحته ويكمّل حسابه.
أبسط مثال كود — factorial
factorial(5) معناها 5 × 4 × 3 × 2 × 1 = 120. كود JavaScript شغّال على Node 22:
function factorial(n) {
// base case: لو وصلنا لـ 1 ارجع مباشرة
if (n <= 1) return 1;
// recursive case: ضرب n في factorial(n-1)
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
console.log(factorial(10)); // 3628800اللي بيحصل لما تنده factorial(5) بالتفاصيل:
factorial(5)محتاج عشان يكمّل، فبيتحط فوق الـ stack وبيستنى.