2009-09-09

A Promise from God

بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

وَمَكَرُواْ مَكْراً وَمَكَرْنَا مَكْراً وَهُمْ لَا يَشْعُرُونَ

فَانظُرْ كَيْفَ كَانَ عَاقِبَةُ مَكْرِهِمْ أَنَّا دَمَّرْنَاهُمْ وَقَوْمَهُمْ أَجْمَعِينَ

فَتِلْكَ بُيُوتُهُمْ خَاوِيَةً بِمَا ظَلَمُواْ إِنَّ فِي ذَلِكَ لَآيَةً لِّقَوْمٍ يَعْلَمُونَ

وَأَنجَيْنَا الَّذِينَ آمَنُواْ وَكَانُواْ يَتَّقُونَ

النمل، 50-53

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)]

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