در این مقاله قصد داریم تا با نحوه استفاده از تکنیک بازگشتی برای توسعه یک تابع بازگشتی در جاوااسکریپت، تابعی که خود را فراخوانی میکند، آشنا شویم.
تابع بازگشتی تابعی است که تا زمان رسیدن به شرط توقف فراخوانی، خود را فراخوانی میکند و این تکنیک بازگشتی نام دارد.
فرض کنید یک تابع به نام recurse()
داریم. recurse()
یک تابع بازگشتی است اگر خود را در داخل بدنه خود فراخوانی کند، به این صورت که:
function recurse() { // ... recurse(); // ... }
یک تابع بازگشتی همیشه یک شرط برای توقف فراخوانی خود دارد، زیرا در غیر این فراخوانی تا بینهایت ادامه خواهد داشت. بنابراین یک تابع بازگشتی معمولاً به شکل زیر است:
function recurse() { if(condition) { // stop calling itself //... } else { recurse(); } }
به طور کلی، ما از توابع بازگشتی برای تجزیه یک مشکل بزرگ به موارد کوچکتر استفاده میکنیم. به طور معمول، توابع بازگشتی را در ساختارهای دادهای مانند درختان باینری و نمودارها و الگوریتمهایی مثل جستجوی باینری و quicksort خواهیم یافت.
در ادامه چند مثال از توابع بازگشتی را باهم بررسی میکنیم.
فرض کنید میخواهیم تابعی بنویسیم که از یک عدد مشخص شروع به شمارش معکوس کند تا به عدد ۱ برسد. برای مثال شمارش معکوس از ۳ به ۱:
۳ ۲ ۱
قطعه کد زیر تابع countDown()
را نشان میدهد:
function countDown(fromNumber) { console.log(fromNumber); } countDown(3);
countDown(3)
فقط عدد ۳ را نشان میدهد.
برای شمارش معکوس از عدد ۳ تا ۱، میتوانیم به ترتیب زیر عمل کنیم:
countDown(2)
که عدد ۲ را نشان میدهد، فراخوانی کنیمcountDown(1)
که عدد ۱ را نشان میدهد، فراخوانی کنیمبه این ترتیب میتوانیم تابع countDown()
را به شکل بازگشتی بنویسیم:
function countDown(fromNumber) { console.log(fromNumber); countDown(fromNumber-1); } countDown(3);
تابع countDown(3)
تا زمانی که از اندازه stack فراخوانی شده فراتر رود، اجرا خواهد شد. در نهایت با خطای زیر مواجه میشویم:
Uncaught RangeError: Maximum call stack size exceeded.
خطایی که رخ میدهد به این دلیل است که هیچ شرطی برای قطع فراخوانی وجود ندارد.
شمارش معکوس زمانی متوقف میشود که عدد بعدی صفر شود. بنابراین برای حل این مشکل یک شرط if را به صورت زیر اضافه میکنیم:
function countDown(fromNumber) { console.log(fromNumber); let nextNumber = fromNumber - 1; if (nextNumber > 0) { countDown(nextNumber); } } countDown(3);
خروجی به شکل زیر خواهد بود:
۳ ۲ ۱
تا این مرحله اینطور بهنظر میرسد که تابع countDown()
مطابق انتظاری که داشتیم کار میکند.
با این حال نام تابع رفرنسی به آبجکت تابع واقعی است. یعنی اگر نام تابع در جایی از کد روی null تنظیم شود، تابع بازگشتی از کار میافتد. به عنوان مثال، کد زیر منجر به یک خطا میشود:
let newYearCountDown = countDown; // somewhere in the code countDown = null; // the following function call will cause an error newYearCountDown(10);
خطا:
Uncaught TypeError: countDown is not a function
نحوه کار قطعه کد بالا:
countDown
را به متغیر newYearCountDown
اختصاص میدهیمcountDown
را روی null تنظیم میکنیمnewYearCountDown
را فراخوانی میکنیماین کد باعث ایجاد خطا میشود زیرا در بدنه تابع countDown()
به نام تابع countDown
اشاره میشود که در زمان فراخوانی تابع روی مقدار null تنظیم شده بود.
برای حل این مشکل میتوانیم از یک عبارت تابع نامگذاری شده به صورت زیر استفاده کنیم:
let countDown = function f(fromNumber) { console.log(fromNumber); let nextNumber = fromNumber - 1; if (nextNumber > 0) { f(nextNumber); } } let newYearCountDown = countDown; countDown = null; newYearCountDown(10);
فرض کنید میخواهیم مجموع اعداد طبیعی از ۱ تا n را با استفاده از تکنیک بازگشتی محاسبه کنیم. برای انجام این کار، باید تابع sum()
را به صورت بازگشتی و به شکل زیر تعریف کنیم:
sum(n) = n + sum(n-1) sum(n-1) = n - 1 + sum(n-2) ... sum(1) = 1
تابع بازگشتی sum()
به صورت زیر است:
function sum(n) { if (n <= 1) { return n; } return n + sum(n - 1); }
دیدگاهها: