2009-01-22

Recursion and Local Variables in JavaScript

Consider the following JavaScript code snippet.

function f(x)
{
 var s = "";
 if(x instanceof Array)
 {
  s += "[";
  for(i = 0; i < x.length; i++) s += f(x[i]);
  s += "]";
 }
 else
 {
  s += "(";
  s += x.toString();
  s += ")";
 }
 return s;
}
alert(f([1, [2, 3, 4], 5]));

If you put this code in an HTML page, you will see that it shows the following result:

[(1)[(2)(3)(4)]]

What's wrong with the code?

The problem is that we have not defined the variable i in the for loop as a local variable. When the function f calls itself recursively, the variable i will have a value from the inner call, and the rest of the loop will not be executed in the outer call.

Now, we add var i; before the loop.

function f(x)
{
 var s = "";
 if(x instanceof Array)
 {
  s += "[";
  var i;
  for(i = 0; i < x.length; i++) s += f(x[i]);
  s += "]";
 }
 else
 {
  s += "(";
  s += x.toString();
  s += ")";
 }
 return s;
}
alert(f([1, [2, 3, 4], 5]));

Here is the result:

[(1)[(2)(3)(4)](5)]

Whenever we use recursion in JavaScript, it is particularly important to take into account the scope of local variables.

تراجع و متغيرهاي محلي در جاوااسكريپت

قطعه‌ي كد جاوااسكريپت زير را در نظر بگيريد.

function f(x)
{
 var s = "";
 if(x instanceof Array)
 {
  s += "[";
  for(i = 0; i < x.length; i++) s += f(x[i]);
  s += "]";
 }
 else
 {
  s += "(";
  s += x.toString();
  s += ")";
 }
 return s;
}
alert(f([1, [2, 3, 4], 5]));

اگر اين كد را در يك صفحه‌ي HTML قرار دهيد، مي‌بينيد كه نتيجه‌ي زير را نشان مي‌دهد:

[(1)[(2)(3)(4)]]

مشكل اين متن برنامه در كجا است؟

مسئله آن است كه ما متغير i را در حلقه‌ي for به عنوان يك متغير محلي تعريف نكرده‌ايم. وقتي كه تابع f خودش را به صورت تراجعي فرا مي‌خواند، متغير i از فراخواني داخلي، داراي مقدار خواهد بود و بقيه‌ي حلقه در فراخواني خارجي اجرا نخواهد شد.

حالا يك سطر var i; قبل از حلقه اضافه مي‌كنيم.

function f(x)
{
 var s = "";
 if(x instanceof Array)
 {
  s += "[";
  var i;
  for(i = 0; i < x.length; i++) s += f(x[i]);
  s += "]";
 }
 else
 {
  s += "(";
  s += x.toString();
  s += ")";
 }
 return s;
}
alert(f([1, [2, 3, 4], 5]));

نتيجه از اين قرار است:

[(1)[(2)(3)(4)](5)]

هر گاه در جاوااسكريپت از تراجع استفاده مي‌كنيم، اين موضوع اهميت خاصي دارد كه به قلمرو متغيرهاي محلي توجه كنيم.