تابع بازگشتی در جاوااسکریپت

در این مقاله قصد داریم تا با نحوه استفاده از تکنیک بازگشتی برای توسعه یک تابع بازگشتی در جاوااسکریپت، تابعی که خود را فراخوانی می‌کند، آشنا شویم.

 توابع بازگشتی در جاوااسکریپت

تابع بازگشتی تابعی است که تا زمان رسیدن به شرط توقف فراخوانی، خود را فراخوانی می‌کند و این تکنیک بازگشتی نام دارد.

فرض کنید یک تابع به نام 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 عدد طبیعی

فرض کنید می‌خواهیم مجموع اعداد طبیعی از ۱ تا 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);
}

جمع‌بندی

  • تابع بازگشتی تابعی است که خود به‌طور مرتب فراخوانی می‌کند.
  • یک تابع بازگشتی همیشه شرطی دارد که آن را از فراخوانی خود باز می‌دارد.

دیدگاه‌ها:

افزودن دیدگاه جدید